internal/core/adt: pass errors up in nested comprehensions
Change-Id: I97449f51f214f36d6bd7db0c69a8001e6c7393d6
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7941
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
diff --git a/cue/testdata/comprehensions/iferror.txtar b/cue/testdata/comprehensions/iferror.txtar
new file mode 100644
index 0000000..dd7403b
--- /dev/null
+++ b/cue/testdata/comprehensions/iferror.txtar
@@ -0,0 +1,94 @@
+-- in.cue --
+a: { b: 2, c: int }
+
+wrongConcreteType: {
+ if a.b {
+ 2
+ }
+}
+
+wrongType: {
+ if a.c {
+ 2
+ }
+}
+
+incomplete: {
+ if a.d {
+ 2
+ }
+}
+
+incomplete: {
+ list: [1, 2, 3]
+ for x in list if a.d {
+ x
+ }
+}
+-- out/compile --
+--- in.cue
+{
+ a: {
+ b: 2
+ c: int
+ }
+ wrongConcreteType: {
+ if 〈1;a〉.b {
+ 2
+ }
+ }
+ wrongType: {
+ if 〈1;a〉.c {
+ 2
+ }
+ }
+ incomplete: {
+ if 〈1;a〉.d {
+ 2
+ }
+ }
+ incomplete: {
+ list: [
+ 1,
+ 2,
+ 3,
+ ]
+ for _, x in 〈0;list〉 if 〈2;a〉.d {
+ 〈1;x〉
+ }
+ }
+}
+-- out/eval --
+Errors:
+wrongConcreteType: cannot use 2 (type int) as type bool:
+ ./in.cue:4:2
+wrongType: cannot use int (type int) as type bool:
+ ./in.cue:10:2
+
+Result:
+(_|_){
+ // [eval]
+ a: (struct){
+ b: (int){ 2 }
+ c: (int){ int }
+ }
+ wrongConcreteType: (_|_){
+ // [eval] wrongConcreteType: cannot use 2 (type int) as type bool:
+ // ./in.cue:4:2
+ }
+ wrongType: (_|_){
+ // [eval] wrongType: cannot use int (type int) as type bool:
+ // ./in.cue:10:2
+ }
+ incomplete: (_|_){
+ // [incomplete] incomplete: undefined field d:
+ // ./in.cue:16:7
+ // incomplete: undefined field d:
+ // ./in.cue:23:21
+ list: (#list){
+ 0: (int){ 1 }
+ 1: (int){ 2 }
+ 2: (int){ 3 }
+ }
+ }
+}
diff --git a/cue/testdata/cycle/comprehension.txtar b/cue/testdata/cycle/comprehension.txtar
index 0dd958e..33454eb 100644
--- a/cue/testdata/cycle/comprehension.txtar
+++ b/cue/testdata/cycle/comprehension.txtar
@@ -12,8 +12,8 @@
}
}
-// TODO(errors): this should result in an incomplete error.
-// A simplified control flow should help here.
+// This should result in an incomplete error (a reference cycle error classifies
+// as incomplete).
B: {
a: {
parent: ""
@@ -64,7 +64,9 @@
B: (struct){
a: (struct){
parent: (string){ "" }
- children: (#list){
+ children: (_|_){
+ // [cycle] cycle error:
+ // ./in.cue:19:47
}
}
}
diff --git a/internal/core/adt/context.go b/internal/core/adt/context.go
index da90d20..0bb10e8 100644
--- a/internal/core/adt/context.go
+++ b/internal/core/adt/context.go
@@ -187,10 +187,9 @@
return c.src.Pos()
}
-func (c *OpContext) spawn(node *Vertex) *OpContext {
- sub := *c
- node.Parent = c.e.Vertex
- sub.e = &Environment{
+func (c *OpContext) spawn(node *Vertex) *Environment {
+ node.Parent = c.e.Vertex // TODO: Is this necessary?
+ return &Environment{
Up: c.e,
Vertex: node,
@@ -199,7 +198,6 @@
Deref: c.e.Deref,
Cycles: c.e.Cycles,
}
- return &sub
}
func (c *OpContext) Env(upCount int32) *Environment {
diff --git a/internal/core/adt/expr.go b/internal/core/adt/expr.go
index cec875a..939ef6e 100644
--- a/internal/core/adt/expr.go
+++ b/internal/core/adt/expr.go
@@ -1251,7 +1251,13 @@
n.Arcs = append(n.Arcs, v)
}
- x.Dst.yield(c.spawn(n), f)
+ sub := c.spawn(n)
+ saved := c.PushState(sub, x.Dst.Source())
+ x.Dst.yield(c, f)
+ if b := c.PopState(saved); b != nil {
+ c.AddBottom(b)
+ break
+ }
if c.HasErr() {
break
}
@@ -1304,7 +1310,13 @@
n := &Vertex{Arcs: []*Vertex{
{Label: x.Label, Conjuncts: []Conjunct{{c.Env(0), x.Expr, 0}}},
}}
- x.Dst.yield(c.spawn(n), f)
+
+ sub := c.spawn(n)
+ saved := c.PushState(sub, x.Dst.Source())
+ x.Dst.yield(c, f)
+ if b := c.PopState(saved); b != nil {
+ c.AddBottom(b)
+ }
}
// A ValueClause represents the value part of a comprehension.