internal/core/eval: fix issue 507
Select default when a disjunction is used in
for loop sources or selection.
Also verify defaults are picked according to
spec in other places.
Fixes #507
Change-Id: I9b29213c412f2e881ac41e9d6fcd2a3ad9334690
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7022
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/testdata/comprehensions/issue507.txtar b/cue/testdata/comprehensions/issue507.txtar
new file mode 100644
index 0000000..c4b6b38
--- /dev/null
+++ b/cue/testdata/comprehensions/issue507.txtar
@@ -0,0 +1,75 @@
+-- in.cue --
+package x
+
+somelist: [...string] | * []
+// Works just fine
+foo: [
+ for e in somelist {
+ "hello foo: \(e)"
+ }
+]
+
+otherlist: ["something"]
+// Works fine as well
+z: [
+ for e in otherlist {
+ "hello z: \(e)"
+ }
+]
+
+extlist: [...string] | * ["something"]
+bar: [
+ for e in extlist {
+ "hello bar: \(e)"
+ }
+]
+-- out/eval --
+(struct){
+ somelist: (#list){
+ }
+ foo: (#list){
+ }
+ otherlist: (#list){
+ 0: (string){ "something" }
+ }
+ z: (#list){
+ 0: (string){ "hello z: something" }
+ }
+ extlist: (list){ |(*(#list){
+ 0: (string){ "something" }
+ }, (list){
+ }) }
+ bar: (#list){
+ 0: (string){ "hello bar: something" }
+ }
+}
+-- out/compile --
+--- in.cue
+{
+ somelist: ([
+ ...string,
+ ]|*[])
+ foo: [
+ for _, e in 〈0;somelist〉 {
+ "hello foo: \(〈1;e〉)"
+ },
+ ]
+ otherlist: [
+ "something",
+ ]
+ z: [
+ for _, e in 〈0;otherlist〉 {
+ "hello z: \(〈1;e〉)"
+ },
+ ]
+ extlist: ([
+ ...string,
+ ]|*[
+ "something",
+ ])
+ bar: [
+ for _, e in 〈0;extlist〉 {
+ "hello bar: \(〈1;e〉)"
+ },
+ ]
+}
diff --git a/cue/testdata/cycle/structural.txtar b/cue/testdata/cycle/structural.txtar
index 97b5575..678384c 100644
--- a/cue/testdata/cycle/structural.txtar
+++ b/cue/testdata/cycle/structural.txtar
@@ -84,6 +84,7 @@
}
d3: {
+ // TODO(errors): position reporting in structural cycle.
config: {
a: b: c: indirect
indirect: [a.b, null][i]
@@ -228,8 +229,6 @@
d1.a.b.c.d.t: structural cycle
d1.r: structural cycle
d2.a.b.c.d.t: structural cycle
-d3.x.a.b.c: structural cycle
-d3.x.indirect: structural cycle
e1.a.c: structural cycle
e1.b.c: structural cycle
e2.a.c: structural cycle
@@ -501,13 +500,20 @@
}
d3: (_|_){
// [structural cycle]
- config: (struct){
- a: (struct){
- b: (struct){
- c: (null){ null }
+ config: (_|_){
+ // [structural cycle]
+ a: (_|_){
+ // [structural cycle]
+ b: (_|_){
+ // [structural cycle]
+ c: (_|_){
+ // [structural cycle]
+ }
}
}
- indirect: (null){ null }
+ indirect: (_|_){
+ // [structural cycle]
+ }
i: (int){ 1 }
}
x: (_|_){
@@ -517,16 +523,12 @@
b: (_|_){
// [structural cycle]
c: (_|_){
- // [structural cycle] d3.x.a.b.c: structural cycle
- c: (_|_){// 〈2;indirect〉
- }
+ // [structural cycle]
}
}
}
indirect: (_|_){
- // [structural cycle] d3.x.indirect: structural cycle
- c: (_|_){// 〈2;indirect〉
- }
+ // [structural cycle]
}
i: (int){ 0 }
}
diff --git a/cue/testdata/disjunctions/operands.txtar b/cue/testdata/disjunctions/operands.txtar
new file mode 100644
index 0000000..3666ce8
--- /dev/null
+++ b/cue/testdata/disjunctions/operands.txtar
@@ -0,0 +1,115 @@
+# This file tests disjunctions used as operands.
+
+-- in.cue --
+
+list: *[1] | [2]
+condition: *true | false
+num: *1 | 2
+object: *{ a: 1 } | { a: 2 }
+
+forLoop: [
+ for e in list {
+ "count: \(e)"
+ }
+]
+
+conditional: {
+ if condition {
+ a: 3
+ }
+ if num < 5 {
+ b: 3
+ }
+}
+
+selector: {
+ a: object.a
+}
+
+index: {
+ a: list[0]
+}
+
+binOp: {
+ a: num + 4
+}
+
+unaryOp: {
+ a: -num
+}
+
+-- out/eval --
+(struct){
+ list: (list){ |(*(#list){
+ 0: (int){ 1 }
+ }, (#list){
+ 0: (int){ 2 }
+ }) }
+ condition: (bool){ |(*(bool){ true }, (bool){ false }) }
+ num: (int){ |(*(int){ 1 }, (int){ 2 }) }
+ object: (struct){ |(*(struct){
+ a: (int){ 1 }
+ }, (struct){
+ a: (int){ 2 }
+ }) }
+ forLoop: (#list){
+ 0: (string){ "count: 1" }
+ }
+ conditional: (struct){
+ a: (int){ 3 }
+ b: (int){ 3 }
+ }
+ selector: (struct){
+ a: (int){ 1 }
+ }
+ index: (struct){
+ a: (int){ 1 }
+ }
+ binOp: (struct){
+ a: (int){ 5 }
+ }
+ unaryOp: (struct){
+ a: (int){ -1 }
+ }
+}
+-- out/compile --
+--- in.cue
+{
+ list: (*[
+ 1,
+ ]|[
+ 2,
+ ])
+ condition: (*true|false)
+ num: (*1|2)
+ object: (*{
+ a: 1
+ }|{
+ a: 2
+ })
+ forLoop: [
+ for _, e in 〈0;list〉 {
+ "count: \(〈1;e〉)"
+ },
+ ]
+ conditional: {
+ if 〈1;condition〉 {
+ a: 3
+ }
+ if (〈1;num〉 < 5) {
+ b: 3
+ }
+ }
+ selector: {
+ a: 〈1;object〉.a
+ }
+ index: {
+ a: 〈1;list〉[0]
+ }
+ binOp: {
+ a: (〈1;num〉 + 4)
+ }
+ unaryOp: {
+ a: -〈1;num〉
+ }
+}
diff --git a/cue/testdata/eval/disjunctions.txtar b/cue/testdata/eval/disjunctions.txtar
index ab8f9ac..6e30441 100644
--- a/cue/testdata/eval/disjunctions.txtar
+++ b/cue/testdata/eval/disjunctions.txtar
@@ -55,7 +55,6 @@
d100: {
// Should we allow a selector to imply a struct or list? Would be convenient.
// This would be a spec change. Disallow for now.
- // TODO(errors): better error message
i: null | {bar: 2}
j: i.bar
}
@@ -154,8 +153,8 @@
bar: (int){ 2 }
}) }
j: (_|_){
- // [incomplete] d100.j: incomplete feed source value i (type (null|struct)):
- // ./in.cue:59:6
+ // [incomplete] d100.j: unresolved disjunction null | {bar:2} (type (null|struct)):
+ // ./in.cue:58:6
}
}
}
diff --git a/internal/core/adt/context.go b/internal/core/adt/context.go
index 7cb2aa0..bdf1af9 100644
--- a/internal/core/adt/context.go
+++ b/internal/core/adt/context.go
@@ -606,6 +606,12 @@
func (c *OpContext) node(x Expr, state VertexStatus) *Vertex {
v := c.evalState(x, state)
+ v, ok := c.getDefault(v)
+ if !ok {
+ // Error already generated by getDefault.
+ return emptyNode
+ }
+
node, ok := v.(*Vertex)
if !ok {
if isError(v) {