Skip to content

Commit 008d37d

Browse files
committed
internal/core/adt: catch errors for circular failures
This mechansim can ultimately also be used for communicating any change that makes a Vertex more specific. Change-Id: Ia5d86fd4cc7da53290998aa5e08de12a474ec440 Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8113 Reviewed-by: CUE cueckoo <[email protected]> Reviewed-by: Marcel van Lohuizen <[email protected]>
1 parent 0c3791e commit 008d37d

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

cue/testdata/cycle/021_delayed_constraint_failure.txtar

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ x: conflicting values 101 and 100:
3636
Result:
3737
(_|_){
3838
// [eval]
39-
a: (int){ 100 }
39+
a: (_|_){
40+
// [eval] b: conflicting values 210 and 200:
41+
// ./in.cue:2:4
42+
// ./in.cue:3:4
43+
}
4044
b: (_|_){
4145
// [eval] b: conflicting values 210 and 200:
4246
// ./in.cue:2:4

cue/testdata/cycle/049_self-reference_cycles_conflicts_with_strings.txtar

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ Result:
4242
// ./in.cue:2:5
4343
// ./in.cue:5:7
4444
}
45-
y: (string){ "hey!" }
45+
y: (_|_){
46+
// [eval] a.x: conflicting values "hey!?" and "hey":
47+
// ./in.cue:2:5
48+
// ./in.cue:5:7
49+
}
4650
}
4751
}

internal/core/adt/eval.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,9 @@ func (e *Unifier) evaluate(c *OpContext, v *Vertex, state VertexStatus) Value {
167167
Conjuncts: v.Conjuncts,
168168
}
169169
w.UpdateStatus(v.Status())
170-
return w
170+
v = w
171171
}
172172
}
173-
return x
174173

175174
case nil:
176175
if v.state != nil {
@@ -186,6 +185,10 @@ func (e *Unifier) evaluate(c *OpContext, v *Vertex, state VertexStatus) Value {
186185
panic("nil value")
187186
}
188187

188+
if v.status < Finalized && v.state != nil {
189+
v.state.addNotify(c.vertex)
190+
}
191+
189192
return v
190193
}
191194

@@ -274,6 +277,8 @@ func (e *Unifier) Unify(c *OpContext, v *Vertex, state VertexStatus) {
274277
for n.maybeSetCache(); n.expandOne(); n.maybeSetCache() {
275278
}
276279

280+
n.doNotify()
281+
277282
if !n.done() {
278283
if len(n.disjunctions) > 0 && v.BaseValue == cycle {
279284
// We disallow entering computations of disjunctions with
@@ -372,6 +377,23 @@ func (e *Unifier) Unify(c *OpContext, v *Vertex, state VertexStatus) {
372377
}
373378
}
374379

380+
func (n *nodeContext) doNotify() {
381+
if n.errs != nil && len(n.notify) > 0 {
382+
for _, v := range n.notify {
383+
if v.state == nil {
384+
if b, ok := v.BaseValue.(*Bottom); ok {
385+
v.BaseValue = CombineErrors(nil, b, n.errs)
386+
} else {
387+
v.BaseValue = n.errs
388+
}
389+
} else {
390+
v.state.addBottom(n.errs)
391+
}
392+
}
393+
n.notify = n.notify[:0]
394+
}
395+
}
396+
375397
func isStruct(v *Vertex) bool {
376398
_, ok := v.BaseValue.(*StructMarker)
377399
return ok
@@ -647,6 +669,10 @@ type nodeContext struct {
647669
checks []Validator // BuiltinValidator, other bound values.
648670
errs *Bottom
649671

672+
// notify is used to communicate errors in cyclic dependencies.
673+
// TODO: also use this to communicate increasingly more concrete values.
674+
notify []*Vertex
675+
650676
// Struct information
651677
dynamicFields []envDynamic
652678
ifClauses []envYield
@@ -671,6 +697,12 @@ type nodeContext struct {
671697
disjunctErrs []*Bottom
672698
}
673699

700+
func (n *nodeContext) addNotify(v *Vertex) {
701+
if v != nil {
702+
n.notify = append(n.notify, v)
703+
}
704+
}
705+
674706
func (n *nodeContext) clone() *nodeContext {
675707
d := n.ctx.Unifier.newNodeContext(n.ctx, n.node)
676708

@@ -696,6 +728,7 @@ func (n *nodeContext) clone() *nodeContext {
696728
d.hasNonCycle = n.hasNonCycle
697729

698730
// d.arcMap = append(d.arcMap, n.arcMap...) // XXX add?
731+
d.notify = append(d.notify, n.notify...)
699732
d.checks = append(d.checks, n.checks...)
700733
d.dynamicFields = append(d.dynamicFields, n.dynamicFields...)
701734
d.ifClauses = append(d.ifClauses, n.ifClauses...)

0 commit comments

Comments
 (0)