Choose disagreement's message from one table over the two items' kinds

This commit is contained in:
2026-10-07 02:10:58 +02:00
committed by Lillem4n
parent fcec9c4a2a
commit 9aec575dca
+45 -22
View File
@@ -150,35 +150,58 @@ func kindOf(t *template) itemKind {
// disagreement names the fix for items a and b of one column holding different datatypes, fixing
// the one that declares least, a when both declare alike.
func disagreement(a *template, da DataType, b *template, db DataType) error {
fix, other, want := a, b, db
c := clash{fix: a, other: b, want: db, held: fmt.Sprintf("its items hold %s and %s; a column holds one datatype", da, db)}
if kindOf(b) < kindOf(a) {
fix, other, want = b, a, da
c.fix, c.other, c.want = b, a, da
}
held := fmt.Sprintf("its items hold %s and %s; a column holds one datatype", da, db)
fits := (&valueProof{}).proveColumnItem(fix).Not[want] == ""
switch kindOf(fix) {
case kindDeclares:
return errors.New(held)
case kindReads:
if fits {
return fmt.Errorf("%s, so %s", held, typedAs(fix, want))
}
return fmt.Errorf("%s, so to read %q as text, %s", held, fix.format, asText(fix))
case kindText:
switch kindOf(other) {
case kindText:
message, ok := disagreements[[2]itemKind{kindOf(c.fix), kindOf(c.other)}]
if !ok {
panic(invariant.Broken("two text items hold one datatype, so they never disagree"))
case kindReads:
if !fits {
return fmt.Errorf(`item %q is not %s, the datatype item %q takes from the column it reads; to read that column as text, %s`, fix.format, datatype.Noun(want), other.format, asText(other))
}
return message(c)
}
if fix.fromString { // an object may carry a weight, which this spelling would drop
return fmt.Errorf(`item %q declares no datatype, and a column holds one; write it as {"format":%q,"datatype":%q}`, fix.format, fix.format, want)
// clash is two items of one column holding different datatypes: fix, the item to fix, beside
// other, which holds want; held says what each holds.
type clash struct {
fix, other *template
want DataType
held string
}
return fmt.Errorf(`item %q declares no datatype beside one holding %s; a column holds one, so give it "datatype": %q`, fix.format, want, want)
// disagreements is a clash's message by the kinds of its items, fix's first.
var disagreements = map[[2]itemKind]func(clash) error{
{kindDeclares, kindDeclares}: clash.bothDeclare,
{kindReads, kindReads}: clash.retypeRead,
{kindReads, kindDeclares}: clash.retypeRead,
{kindText, kindReads}: clash.textBesideRead,
{kindText, kindDeclares}: clash.declareText,
}
panic(invariant.Broken("disagreement has no case for item kind %d", kindOf(fix)))
func (c clash) bothDeclare() error { return errors.New(c.held) }
// fits reports whether fix may hold want.
func (c clash) fits() bool { return (&valueProof{}).proveColumnItem(c.fix).Not[c.want] == "" }
func (c clash) retypeRead() error {
if c.fits() {
return fmt.Errorf("%s, so %s", c.held, typedAs(c.fix, c.want))
}
return fmt.Errorf("%s, so to read %q as text, %s", c.held, c.fix.format, asText(c.fix))
}
func (c clash) textBesideRead() error {
if !c.fits() {
return fmt.Errorf(`item %q is not %s, the datatype item %q takes from the column it reads; to read that column as text, %s`, c.fix.format, datatype.Noun(c.want), c.other.format, asText(c.other))
}
return c.declareText()
}
func (c clash) declareText() error {
if c.fix.fromString { // an object may carry a weight, which this spelling would drop
return fmt.Errorf(`item %q declares no datatype, and a column holds one; write it as {"format":%q,"datatype":%q}`, c.fix.format, c.fix.format, c.want)
}
return fmt.Errorf(`item %q declares no datatype beside one holding %s; a column holds one, so give it "datatype": %q`, c.fix.format, c.want, c.want)
}
// typedAs names the spelling giving a column-read item datatype d, keeping the other keys an object