Skip to content

Commit d55e2b5

Browse files
committed
internal/core/eval: allow lists resulting from dependent expressions
Fixes #494 Change-Id: I4d9e92193156e39e8677ba091250a73881d141b0 Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6962 Reviewed-by: Marcel van Lohuizen <[email protected]> Reviewed-by: CUE cueckoo <[email protected]>
1 parent 1c54297 commit d55e2b5

File tree

2 files changed

+220
-9
lines changed

2 files changed

+220
-9
lines changed

cue/testdata/cycle/issue494.txtar

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
-- in.cue --
2+
_Q : [{pos: 0},{pos: 1}]
3+
4+
a: [rn=string]: _Q[0:len(a[rn])]
5+
a: ben: [{}]
6+
7+
b: [rn=string]: _Q[0:1]
8+
b: ben: [{}]
9+
10+
c: [rn=string]: [...{l: len(a[rn])}]
11+
c: ben: [{}]
12+
13+
#d: [rn=string]: [...{pos:uint}] & _Q[0:len(#d[rn])]
14+
#d: ben: [{}]
15+
16+
d: #d
17+
18+
e: [rn=string]: _Q[0:len(a[rn])+1]
19+
e: ben: [{}, ...]
20+
21+
f: [rn=string]: _Q[0:len(a[rn])+1]
22+
f: ben: [{}]
23+
24+
g: [rn=string]: _Q[0:len(a[rn])]
25+
g: ben: [{}, {}]
26+
27+
-- out/eval --
28+
Errors:
29+
f.ben: incompatible list lengths (1 and 2)
30+
g.ben: incompatible list lengths (1 and 2)
31+
32+
Result:
33+
(_|_){
34+
// [eval]
35+
_Q: (#list){
36+
0: (struct){
37+
pos: (int){ 0 }
38+
}
39+
1: (struct){
40+
pos: (int){ 1 }
41+
}
42+
}
43+
a: (struct){
44+
ben: (#list){
45+
0: (struct){
46+
pos: (int){ 0 }
47+
}
48+
}
49+
}
50+
b: (struct){
51+
ben: (#list){
52+
0: (struct){
53+
pos: (int){ 0 }
54+
}
55+
}
56+
}
57+
c: (struct){
58+
ben: (#list){
59+
0: (struct){
60+
l: (int){ 1 }
61+
}
62+
}
63+
}
64+
#d: (#struct){
65+
ben: (#list){
66+
0: (#struct){
67+
pos: (int){ 0 }
68+
}
69+
}
70+
}
71+
d: (#struct){
72+
ben: (#list){
73+
0: (#struct){
74+
pos: (int){ 0 }
75+
}
76+
}
77+
}
78+
e: (struct){
79+
ben: (#list){
80+
0: (struct){
81+
pos: (int){ 0 }
82+
}
83+
1: (struct){
84+
pos: (int){ 1 }
85+
}
86+
}
87+
}
88+
f: (_|_){
89+
// [eval]
90+
ben: (_|_){
91+
// [eval] f.ben: incompatible list lengths (1 and 2)
92+
0: (struct){
93+
pos: (int){ 0 }
94+
}
95+
1: (struct){
96+
pos: (int){ 1 }
97+
}
98+
}
99+
}
100+
g: (_|_){
101+
// [eval]
102+
ben: (_|_){
103+
// [eval] g.ben: incompatible list lengths (1 and 2)
104+
0: (struct){
105+
pos: (int){ 0 }
106+
}
107+
1: (struct){
108+
}
109+
}
110+
}
111+
}
112+
-- out/compile --
113+
--- in.cue
114+
{
115+
_Q: [
116+
{
117+
pos: 0
118+
},
119+
{
120+
pos: 1
121+
},
122+
]
123+
a: {
124+
[string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])]
125+
}
126+
a: {
127+
ben: [
128+
{},
129+
]
130+
}
131+
b: {
132+
[string]: 〈1;_Q〉[0:1]
133+
}
134+
b: {
135+
ben: [
136+
{},
137+
]
138+
}
139+
c: {
140+
[string]: [
141+
...{
142+
l: len(〈2;a〉[〈1;-〉])
143+
},
144+
]
145+
}
146+
c: {
147+
ben: [
148+
{},
149+
]
150+
}
151+
#d: {
152+
[string]: ([
153+
...{
154+
pos: &(int, >=0)
155+
},
156+
] & 〈1;_Q〉[0:len(〈1;#d〉[〈0;-〉])])
157+
}
158+
#d: {
159+
ben: [
160+
{},
161+
]
162+
}
163+
d: 〈0;#d〉
164+
e: {
165+
[string]: 〈1;_Q〉[0:(len(〈1;a〉[〈0;-〉]) + 1)]
166+
}
167+
e: {
168+
ben: [
169+
{},
170+
...,
171+
]
172+
}
173+
f: {
174+
[string]: 〈1;_Q〉[0:(len(〈1;a〉[〈0;-〉]) + 1)]
175+
}
176+
f: {
177+
ben: [
178+
{},
179+
]
180+
}
181+
g: {
182+
[string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])]
183+
}
184+
g: {
185+
ben: [
186+
{},
187+
{},
188+
]
189+
}
190+
}

internal/core/eval/eval.go

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -420,13 +420,18 @@ func isStruct(v *adt.Vertex) bool {
420420
func (n *nodeContext) postDisjunct() {
421421
ctx := n.ctx
422422

423-
// Use maybeSetCache for cycle breaking
424-
for n.maybeSetCache(); n.expandOne(); n.maybeSetCache() {
425-
}
423+
for {
424+
// Use maybeSetCache for cycle breaking
425+
for n.maybeSetCache(); n.expandOne(); n.maybeSetCache() {
426+
}
426427

427-
if aList := n.addLists(ctx); aList != nil {
428-
n.updateNodeType(adt.ListKind, aList)
428+
if aList := n.addLists(ctx); aList != nil {
429+
n.updateNodeType(adt.ListKind, aList)
430+
} else {
431+
break
432+
}
429433
}
434+
430435
if n.aStruct != nil {
431436
n.updateNodeType(adt.StructKind, n.aStruct)
432437
}
@@ -1600,6 +1605,11 @@ func (n *nodeContext) addLists(c *adt.OpContext) (oneOfTheLists adt.Expr) {
16001605
max := 0
16011606
var maxNode adt.Expr
16021607

1608+
if m, ok := n.node.Value.(*adt.ListMarker); ok {
1609+
isOpen = m.IsOpen
1610+
max = len(n.node.Arcs)
1611+
}
1612+
16031613
for _, l := range n.vLists {
16041614
oneOfTheLists = l
16051615

@@ -1747,10 +1757,21 @@ outer:
17471757

17481758
n.openList = isOpen
17491759

1750-
n.node.SetValue(c, adt.Partial, &adt.ListMarker{
1751-
Src: ast.NewBinExpr(token.AND, sources...),
1752-
IsOpen: isOpen,
1753-
})
1760+
if m, ok := n.node.Value.(*adt.ListMarker); !ok {
1761+
n.node.SetValue(c, adt.Partial, &adt.ListMarker{
1762+
Src: ast.NewBinExpr(token.AND, sources...),
1763+
IsOpen: isOpen,
1764+
})
1765+
} else {
1766+
if expr, _ := m.Src.(ast.Expr); expr != nil {
1767+
sources = append(sources, expr)
1768+
}
1769+
m.Src = ast.NewBinExpr(token.AND, sources...)
1770+
m.IsOpen = m.IsOpen && isOpen
1771+
}
1772+
1773+
n.lists = n.lists[:0]
1774+
n.vLists = n.vLists[:0]
17541775

17551776
return oneOfTheLists
17561777
}

0 commit comments

Comments
 (0)