Skip to content

Commit 6b37a01

Browse files
committed
internal/core/adt: get rid of NotExistError
And replace it with a field. Note that this does not fully fix the below error, as the error is still incorrectly marked as an incomplete error. Issue #1509 Signed-off-by: Marcel van Lohuizen <mpvl@golang.org> Change-Id: I419705b0e67fd960c65f67befd0611542edbb503 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/532871 Unity-Result: CUEcueckoo <cueckoo@cuelang.org> TryBot-Result: CUEcueckoo <cueckoo@cuelang.org> Reviewed-by: Paul Jolly <paul@myitcv.io> Reviewed-by: Marcel van Lohuizen <mpvl@gmail.com>
1 parent 8dee602 commit 6b37a01

File tree

10 files changed

+93
-18
lines changed

10 files changed

+93
-18
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#Issue: 1509
2+
3+
# TODO: recognize when an unresolved value
4+
5+
# export
6+
! exec cue export
7+
cmp stderr expect-stderr1
8+
cmp stdout expect-stdout1
9+
10+
# eval
11+
exec cue eval
12+
cmp stderr expect-stderr2
13+
cmp stdout expect-stdout2
14+
15+
-- x.cue --
16+
package x
17+
18+
import "list"
19+
20+
x: [1, 2, 3]
21+
// This should be a fatal error, as the passed struct will never be
22+
// able to contain `less` by making the configuration more concrete.
23+
sortedx: list.Sort(x, {})
24+
25+
-- expect-stdout1 --
26+
-- expect-stderr1 --
27+
error in call to list.Sort: field not found: less:
28+
./x.cue:8:10
29+
-- expect-stdout2 --
30+
import "list"
31+
32+
x: [1, 2, 3]
33+
sortedx: list.Sort(x, {})
34+
-- expect-stderr2 --
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#Issue: 1509
2+
3+
# export
4+
! exec cue export
5+
cmp stderr expect-stderr1
6+
cmp stdout expect-stdout1
7+
8+
# eval
9+
exec cue eval
10+
cmp stderr expect-stderr2
11+
cmp stdout expect-stdout2
12+
13+
-- x.cue --
14+
package x
15+
16+
import "list"
17+
18+
x: [1, 2, 3]
19+
sortedx: list.Sort(x, cmp)
20+
21+
cmp: {}
22+
23+
-- expect-stdout1 --
24+
-- expect-stderr1 --
25+
error in call to list.Sort: field not found: less:
26+
./x.cue:6:10
27+
-- expect-stdout2 --
28+
import "list"
29+
30+
x: [1, 2, 3]
31+
sortedx: list.Sort(x, cmp)
32+
cmp: {}
33+
-- expect-stderr2 --

cue/errors.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ func (e *valueError) Path() (a []string) {
9191
}
9292

9393
var errNotExists = &adt.Bottom{
94-
Code: adt.NotExistError,
95-
Err: errors.Newf(token.NoPos, "undefined value"),
94+
Code: adt.IncompleteError,
95+
NotExists: true,
96+
Err: errors.Newf(token.NoPos, "undefined value"),
9697
}
9798

9899
func mkErr(idx *runtime.Runtime, src adt.Node, args ...interface{}) *adt.Bottom {

cue/path_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func TestPaths(t *testing.T) {
7777
}, {
7878
path: ParsePath("#Foo.a.c"),
7979
str: "#Foo.a.c",
80-
out: `_|_ // field "c" not found`,
80+
out: `_|_ // field not found: c`,
8181
}, {
8282
path: ParsePath(`b[2]`),
8383
str: `b[2]`,

cue/query.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ outer:
7171
if err, ok := sel.sel.(pathError); ok {
7272
x = &adt.Bottom{Err: err.Error}
7373
} else {
74-
// TODO: better message.
75-
x = mkErr(v.idx, n, adt.NotExistError, "field %q not found", sel.sel)
74+
x = mkErr(v.idx, n, adt.EvalError, "field not found: %v", sel.sel)
75+
if n.Accept(ctx, f) {
76+
x.Code = adt.IncompleteError
77+
}
78+
x.NotExists = true
7679
}
7780
v := makeValue(v.idx, n, parent)
7881
return newErrValue(v, x)

cue/query_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ func TestLookupPath(t *testing.T) {
5353
}, {
5454
in: `_foo: 3`,
5555
path: cue.MakePath(cue.Def("_foo")),
56-
err: `field "#_foo" not found`,
56+
err: `field not found: #_foo`,
5757
}, {
5858
in: `_#foo: 3`,
5959
path: cue.MakePath(cue.Def("_#foo")),
60-
err: `field "_#foo" not found`,
60+
err: `field not found: _#foo`,
6161
}, {
6262
in: `"foo", #foo: 3`,
6363
path: cue.ParsePath("#foo"),
@@ -104,7 +104,7 @@ func TestLookupPath(t *testing.T) {
104104
[Name=string]: { a: Name }
105105
`,
106106
path: cue.MakePath(cue.Str("a")),
107-
err: `field "a" not found`,
107+
err: `field not found: a`,
108108
}}
109109
for _, tc := range testCases {
110110
t.Run(tc.path.String(), func(t *testing.T) {

cue/types.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,15 @@ func (o *hiddenStructValue) Lookup(key string) Value {
137137
}
138138
}
139139
if i == len {
140-
// TODO: better message.
141-
x := mkErr(o.v.idx, o.obj, adt.NotExistError, "value %q not found", key)
140+
x := mkErr(o.v.idx, o.obj, 0, "field not found: %v", key)
141+
x.NotExists = true
142+
// TODO: more specifically we should test whether the values that
143+
// are addressable from the root of the configuration can support the
144+
// looked up value. This will avoid false positives such as when
145+
// an open literal struct is passed to a builtin.
146+
if o.obj.Accept(o.ctx, f) {
147+
x.Code = adt.IncompleteError
148+
}
142149
return newErrValue(o.v, x)
143150
}
144151
return newChildValue(o, i)
@@ -1165,7 +1172,7 @@ func (v Value) Exists() bool {
11651172
return false
11661173
}
11671174
if err, ok := v.v.BaseValue.(*adt.Bottom); ok {
1168-
return err.Code != adt.NotExistError
1175+
return !err.NotExists
11691176
}
11701177
return true
11711178
}

cue/types_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,11 +1516,11 @@ func TestValue_LookupDef(t *testing.T) {
15161516
}, {
15171517
in: `_foo: 3`,
15181518
def: "_foo",
1519-
out: `_|_ // field "#_foo" not found`,
1519+
out: `_|_ // field not found: #_foo`,
15201520
}, {
15211521
in: `_#foo: 3`,
15221522
def: "_#foo",
1523-
out: `_|_ // field "_#foo" not found`,
1523+
out: `_|_ // field not found: _#foo`,
15241524
}, {
15251525
in: `"foo", #foo: 3`,
15261526
def: "#foo",

internal/core/adt/errors.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ const (
4949
// A UserError is a fatal error originating from the user.
5050
UserError
5151

52-
// NotExistError is used to indicate a value does not exist.
53-
// Mostly used for legacy reasons.
54-
NotExistError
55-
5652
// StructuralCycleError means a structural cycle was found. Structural
5753
// cycles are permanent errors, but they are not passed up recursively,
5854
// as a unification of a value with a structural cycle with one that
@@ -96,6 +92,7 @@ type Bottom struct {
9692
Code ErrorCode
9793
HasRecursive bool
9894
ChildError bool // Err is the error of the child
95+
NotExists bool // This error originated from a failed lookup.
9996
// Value holds the computed value so far in case
10097
Value Value
10198
}

internal/core/validate/validate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func (v *validator) validate(x *adt.Vertex) {
7474
v.add(b)
7575
}
7676

77-
case adt.IncompleteError, adt.NotExistError:
77+
case adt.IncompleteError:
7878
if v.checkConcrete() {
7979
v.add(b)
8080
}

0 commit comments

Comments
 (0)