Skip to content

Commit

Permalink
internal/core/eval: allow lists resulting from dependent expressions
Browse files Browse the repository at this point in the history
Fixes #494

Change-Id: I4d9e92193156e39e8677ba091250a73881d141b0
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6962
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
  • Loading branch information
mpvl committed Sep 10, 2020
1 parent 1c54297 commit d55e2b5
Show file tree
Hide file tree
Showing 2 changed files with 220 additions and 9 deletions.
190 changes: 190 additions & 0 deletions cue/testdata/cycle/issue494.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
-- in.cue --
_Q : [{pos: 0},{pos: 1}]

a: [rn=string]: _Q[0:len(a[rn])]
a: ben: [{}]

b: [rn=string]: _Q[0:1]
b: ben: [{}]

c: [rn=string]: [...{l: len(a[rn])}]
c: ben: [{}]

#d: [rn=string]: [...{pos:uint}] & _Q[0:len(#d[rn])]
#d: ben: [{}]

d: #d

e: [rn=string]: _Q[0:len(a[rn])+1]
e: ben: [{}, ...]

f: [rn=string]: _Q[0:len(a[rn])+1]
f: ben: [{}]

g: [rn=string]: _Q[0:len(a[rn])]
g: ben: [{}, {}]

-- out/eval --
Errors:
f.ben: incompatible list lengths (1 and 2)
g.ben: incompatible list lengths (1 and 2)

Result:
(_|_){
// [eval]
_Q: (#list){
0: (struct){
pos: (int){ 0 }
}
1: (struct){
pos: (int){ 1 }
}
}
a: (struct){
ben: (#list){
0: (struct){
pos: (int){ 0 }
}
}
}
b: (struct){
ben: (#list){
0: (struct){
pos: (int){ 0 }
}
}
}
c: (struct){
ben: (#list){
0: (struct){
l: (int){ 1 }
}
}
}
#d: (#struct){
ben: (#list){
0: (#struct){
pos: (int){ 0 }
}
}
}
d: (#struct){
ben: (#list){
0: (#struct){
pos: (int){ 0 }
}
}
}
e: (struct){
ben: (#list){
0: (struct){
pos: (int){ 0 }
}
1: (struct){
pos: (int){ 1 }
}
}
}
f: (_|_){
// [eval]
ben: (_|_){
// [eval] f.ben: incompatible list lengths (1 and 2)
0: (struct){
pos: (int){ 0 }
}
1: (struct){
pos: (int){ 1 }
}
}
}
g: (_|_){
// [eval]
ben: (_|_){
// [eval] g.ben: incompatible list lengths (1 and 2)
0: (struct){
pos: (int){ 0 }
}
1: (struct){
}
}
}
}
-- out/compile --
--- in.cue
{
_Q: [
{
pos: 0
},
{
pos: 1
},
]
a: {
[string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])]
}
a: {
ben: [
{},
]
}
b: {
[string]: 〈1;_Q〉[0:1]
}
b: {
ben: [
{},
]
}
c: {
[string]: [
...{
l: len(〈2;a〉[〈1;-〉])
},
]
}
c: {
ben: [
{},
]
}
#d: {
[string]: ([
...{
pos: &(int, >=0)
},
] & 〈1;_Q〉[0:len(〈1;#d〉[〈0;-〉])])
}
#d: {
ben: [
{},
]
}
d: 〈0;#d〉
e: {
[string]: 〈1;_Q〉[0:(len(〈1;a〉[〈0;-〉]) + 1)]
}
e: {
ben: [
{},
...,
]
}
f: {
[string]: 〈1;_Q〉[0:(len(〈1;a〉[〈0;-〉]) + 1)]
}
f: {
ben: [
{},
]
}
g: {
[string]: 〈1;_Q〉[0:len(〈1;a〉[〈0;-〉])]
}
g: {
ben: [
{},
{},
]
}
}
39 changes: 30 additions & 9 deletions internal/core/eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,13 +420,18 @@ func isStruct(v *adt.Vertex) bool {
func (n *nodeContext) postDisjunct() {
ctx := n.ctx

// Use maybeSetCache for cycle breaking
for n.maybeSetCache(); n.expandOne(); n.maybeSetCache() {
}
for {
// Use maybeSetCache for cycle breaking
for n.maybeSetCache(); n.expandOne(); n.maybeSetCache() {
}

if aList := n.addLists(ctx); aList != nil {
n.updateNodeType(adt.ListKind, aList)
if aList := n.addLists(ctx); aList != nil {
n.updateNodeType(adt.ListKind, aList)
} else {
break
}
}

if n.aStruct != nil {
n.updateNodeType(adt.StructKind, n.aStruct)
}
Expand Down Expand Up @@ -1600,6 +1605,11 @@ func (n *nodeContext) addLists(c *adt.OpContext) (oneOfTheLists adt.Expr) {
max := 0
var maxNode adt.Expr

if m, ok := n.node.Value.(*adt.ListMarker); ok {
isOpen = m.IsOpen
max = len(n.node.Arcs)
}

for _, l := range n.vLists {
oneOfTheLists = l

Expand Down Expand Up @@ -1747,10 +1757,21 @@ outer:

n.openList = isOpen

n.node.SetValue(c, adt.Partial, &adt.ListMarker{
Src: ast.NewBinExpr(token.AND, sources...),
IsOpen: isOpen,
})
if m, ok := n.node.Value.(*adt.ListMarker); !ok {
n.node.SetValue(c, adt.Partial, &adt.ListMarker{
Src: ast.NewBinExpr(token.AND, sources...),
IsOpen: isOpen,
})
} else {
if expr, _ := m.Src.(ast.Expr); expr != nil {
sources = append(sources, expr)
}
m.Src = ast.NewBinExpr(token.AND, sources...)
m.IsOpen = m.IsOpen && isOpen
}

n.lists = n.lists[:0]
n.vLists = n.vLists[:0]

return oneOfTheLists
}
Expand Down

0 comments on commit d55e2b5

Please sign in to comment.