cue: fix premature fixing of some incomplete values
Also tightens structural subsumption (mostly
of cosmetic relevance).
Change-Id: I826d5593907db5a30028a5d99da2f0d255c4f1b8
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2954
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/errors.go b/cue/errors.go
index 5335733..9ab8bb3 100644
--- a/cue/errors.go
+++ b/cue/errors.go
@@ -203,6 +203,7 @@
if v, ok := src.(value); ok {
e.value = v
}
+outer:
for i, a := range args {
switch x := a.(type) {
case errCode:
@@ -219,7 +220,7 @@
for i, a := range e.args {
e.args[i] = fixArg(idx, a)
}
- return e
+ break outer
}
}
if e.code == codeNone && e.wrapped != nil {
diff --git a/cue/eval.go b/cue/eval.go
index bfb2207..5b4a56c 100644
--- a/cue/eval.go
+++ b/cue/eval.go
@@ -202,6 +202,9 @@
}
v := x.value.evalPartial(ctx)
if isBottom(v) {
+ if isIncomplete(v) {
+ return v
+ }
return ctx.mkErr(x, v, "error evaluating bound")
}
if v == x.value {
@@ -445,15 +448,12 @@
d.d = -d.d
return &d
}
- fallthrough
+ return ctx.mkErr(src, codeIncomplete, "operand %s of '-' not concrete (was %s)", ctx.str(x), kind)
case opAdd:
if kind&numeric == bottomKind {
return ctx.mkErr(src, "invalid operation +%s (+ %s)", ctx.str(x), kind)
}
- if kind&^(numeric|nonGround|referenceKind) == bottomKind {
- return v
- }
switch v := v.(type) {
case *numLit, *durationLit:
return v
@@ -462,19 +462,17 @@
case *basicType:
return &basicType{v.baseValue, (v.k & numeric) | nonGround}
}
+ return ctx.mkErr(src, codeIncomplete, "operand %s of '+' not concrete (was %s)", ctx.str(x), kind)
case opNot:
if kind&boolKind == bottomKind {
return ctx.mkErr(src, "invalid operation !%s (! %s)", ctx.str(x), kind)
}
switch v := v.(type) {
- case *top:
- return &basicType{v.baseValue, boolKind | nonGround}
- case *basicType:
- return v
case *boolLit:
return &boolLit{src.base(), !v.b}
}
+ return ctx.mkErr(src, codeIncomplete, "operand %s of '!' not concrete (was %s)", ctx.str(x), kind)
}
return ctx.mkErr(src, "invalid operation %s%s (%s %s)", op, ctx.str(x), op, kind)
}
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index 84d63a7..92c781c 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -2145,6 +2145,43 @@
`b2: (0 | 1), ` +
`c1: (<2>{a: 1, b: 2} | <3>{a: 2, b: 1}), ` +
`c2: (<4>{a: 2, b: 1} | <5>{a: 1, b: 2})}`,
+ }, {
+ desc: "don't convert incomplete errors to non-incomplete",
+ in: `
+ import "strings"
+
+ n1: {min: <max, max: >min}
+ n2: -num
+ n3: +num
+ n4: num + num
+ n5: num - num
+ n6: num * num
+ n7: num / num
+
+ b1: !is
+
+ s1: "\(str)"
+ s2: strings.ContainsAny("dd")
+ s3: strings.ContainsAny(str, "dd")
+
+ str: string
+ num: <4
+ is: bool
+ `,
+ out: `<0>{` +
+ `n1: <1>{min: <<2>.max, max: ><2>.min}, ` +
+ `n2: -<3>.num, num: <4, ` +
+ `n3: +<3>.num, ` +
+ `n4: (<3>.num + <3>.num), ` +
+ `n5: (<3>.num - <3>.num), ` +
+ `n6: (<3>.num * <3>.num), ` +
+ `n7: (<3>.num / <3>.num), ` +
+ `b1: !<3>.is, ` +
+ `is: bool, ` +
+ `s1: ""+<3>.str+"", ` +
+ `str: string, ` +
+ `s2: strings.ContainsAny ("dd"), ` +
+ `s3: <4>.ContainsAny (<3>.str,"dd")}`,
}}
rewriteHelper(t, testCases, evalFull)
}
diff --git a/cue/subsume_test.go b/cue/subsume_test.go
index 97dd9eb..176b092 100644
--- a/cue/subsume_test.go
+++ b/cue/subsume_test.go
@@ -159,17 +159,17 @@
// TODO: may be false if we allow arithmetic on incomplete values.
98: {subsumes: false, in: `a: int + int, b: int * int`},
- 99: {subsumes: true, in: `a: !int, b: !int`},
- 100: {subsumes: true, in: `a: !number, b: !int`},
// TODO: allow subsumption of unevaluated values?
// true because both evaluate to bottom
+ 99: {subsumes: true, in: `a: !int, b: !int`},
+ 100: {subsumes: true, in: `a: !number, b: !int`},
101: {subsumes: true, in: `a: !int, b: !number`},
+
// TODO: allow subsumption of unevaluated values?
- // May be true because both evaluate to bottom. false is always allowed.
102: {subsumes: false, in: `a: int + int, b: !number`},
// TODO: allow subsumption of unevaluated values?
- // true because both evaluate to bool
- 103: {subsumes: true, in: `a: !bool, b: bool`},
+ 103: {subsumes: false, in: `a: !bool, b: bool`},
+ 104: {subsumes: true, in: `a: !bool, b: !bool`},
// Call
113: {subsumes: true, in: `