Skip to content

Commit 4a3a494

Browse files
committed
internal/core/adt: make some errors semi-permanent
An incomplete error indicates the error may be resolved by making a configuration more specific. However, sometimes, during partial evaluation, an incomplete error may arise because a value is not fully evaluated yet to the point the incomplete error may still resolve upon further evaluation. In this change we make some distinctions between these cases to prevent non-applicable error messages from bubbling up and rather propagate applicable error messages more strictly. This may also have a positive impact on performance, as less incomplete evaluations need to be "retried". Fixes #1837 Issue #804 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: I2d1a7876d626da5b4a32db8e1cd6cd9b87eb63e9 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/543574 Reviewed-by: Aram Hăvărneanu <[email protected]> Unity-Result: CUEcueckoo <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent 53dfffa commit 4a3a494

File tree

4 files changed

+93
-5
lines changed

4 files changed

+93
-5
lines changed

cue/testdata/eval/incomplete.txtar

+78
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,32 @@ E: {
1717

1818
a: int
1919
okay: (>10 & <a) + 3
20+
21+
issue1837: {
22+
// x is properly recognized as erroneous and the "message" field is added
23+
// with the value "a", instead of as a cycle error.
24+
p1: {
25+
context: {}
26+
x: context.b // incomplete error
27+
if x == _|_ {
28+
message: "a"
29+
}
30+
}
31+
p2: {
32+
if x == _|_ {
33+
message: "a"
34+
}
35+
x: context.b // incomplete error
36+
context: {}
37+
}
38+
p3: {
39+
if x == _|_ {
40+
message: "a"
41+
}
42+
context: {}
43+
x: context.b // incomplete error
44+
}
45+
}
2046
-- out/eval --
2147
(struct){
2248
s: (string){ string }
@@ -58,6 +84,35 @@ okay: (>10 & <a) + 3
5884
// ./in.cue:18:7
5985
// ./in.cue:18:8
6086
}
87+
issue1837: (struct){
88+
p1: (struct){
89+
message: (string){ "a" }
90+
context: (struct){
91+
}
92+
x: (_|_){
93+
// [incomplete] issue1837.p1.x: undefined field: b:
94+
// ./in.cue:25:14
95+
}
96+
}
97+
p2: (struct){
98+
message: (string){ "a" }
99+
x: (_|_){
100+
// [incomplete] issue1837.p2.x: undefined field: b:
101+
// ./in.cue:34:14
102+
}
103+
context: (struct){
104+
}
105+
}
106+
p3: (struct){
107+
message: (string){ "a" }
108+
context: (struct){
109+
}
110+
x: (_|_){
111+
// [incomplete] issue1837.p3.x: undefined field: b:
112+
// ./in.cue:42:14
113+
}
114+
}
115+
}
61116
}
62117
-- out/compile --
63118
--- in.cue
@@ -76,4 +131,27 @@ okay: (>10 & <a) + 3
76131
}
77132
a: int
78133
okay: ((>10 & <〈0;a〉) + 3)
134+
issue1837: {
135+
p1: {
136+
context: {}
137+
x: 〈0;context〉.b
138+
if (〈0;x〉 == _|_(explicit error (_|_ literal) in source)) {
139+
message: "a"
140+
}
141+
}
142+
p2: {
143+
if (〈0;x〉 == _|_(explicit error (_|_ literal) in source)) {
144+
message: "a"
145+
}
146+
x: 〈0;context〉.b
147+
context: {}
148+
}
149+
p3: {
150+
if (〈0;x〉 == _|_(explicit error (_|_ literal) in source)) {
151+
message: "a"
152+
}
153+
context: {}
154+
x: 〈0;context〉.b
155+
}
156+
}
79157
}

internal/core/adt/context.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -890,17 +890,23 @@ func (c *OpContext) lookup(x *Vertex, pos token.Pos, l Feature, state VertexStat
890890

891891
// TODO(errors): add path reference and make message
892892
// "undefined field %s in %s"
893+
var err *ValueError
893894
if l.IsInt() {
894-
c.addErrf(code, pos, "index out of range [%d] with length %d",
895+
err = c.NewPosf(pos, "index out of range [%d] with length %d",
895896
l.Index(), len(x.Elems()))
896897
} else {
897898
if code != 0 && x.IsOptional(l) {
898-
c.addErrf(code, pos,
899+
err = c.NewPosf(pos,
899900
"cannot reference optional field: %s", label)
900901
} else {
901-
c.addErrf(code, pos, "undefined field: %s", label)
902+
err = c.NewPosf(pos, "undefined field: %s", label)
902903
}
903904
}
905+
c.AddBottom(&Bottom{
906+
Code: code,
907+
Permanent: x.status >= AllArcs,
908+
Err: err,
909+
})
904910
}
905911
return a
906912
}

internal/core/adt/errors.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ type Bottom struct {
8989
Src ast.Node
9090
Err errors.Error
9191

92-
Code ErrorCode
92+
Code ErrorCode
93+
// Permanent indicates whether an incomplete error can be
94+
// resolved later without making the configuration more specific.
95+
// This may happen when an arc isn't fully resolved yet.
96+
Permanent bool
9397
HasRecursive bool
9498
ChildError bool // Err is the error of the child
9599
NotExists bool // This error originated from a failed lookup.

internal/core/adt/eval.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1390,7 +1390,7 @@ func (n *nodeContext) evalExpr(v Conjunct) {
13901390
switch x := v.Expr().(type) {
13911391
case Resolver:
13921392
arc, err := ctx.Resolve(v, x)
1393-
if err != nil && !err.IsIncomplete() {
1393+
if err != nil && (!err.IsIncomplete() || err.Permanent) {
13941394
n.addBottom(err)
13951395
break
13961396
}

0 commit comments

Comments
 (0)