Skip to content
This repository has been archived by the owner on Nov 18, 2021. It is now read-only.

Commit

Permalink
internal/core/adt: catch errors for circular failures
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
mpvl committed Jan 9, 2021
1 parent 0c3791e commit 008d37d
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 4 deletions.
6 changes: 5 additions & 1 deletion cue/testdata/cycle/021_delayed_constraint_failure.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ x: conflicting values 101 and 100:
Result:
(_|_){
// [eval]
a: (int){ 100 }
a: (_|_){
// [eval] b: conflicting values 210 and 200:
// ./in.cue:2:4
// ./in.cue:3:4
}
b: (_|_){
// [eval] b: conflicting values 210 and 200:
// ./in.cue:2:4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ Result:
// ./in.cue:2:5
// ./in.cue:5:7
}
y: (string){ "hey!" }
y: (_|_){
// [eval] a.x: conflicting values "hey!?" and "hey":
// ./in.cue:2:5
// ./in.cue:5:7
}
}
}
37 changes: 35 additions & 2 deletions internal/core/adt/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,9 @@ func (e *Unifier) evaluate(c *OpContext, v *Vertex, state VertexStatus) Value {
Conjuncts: v.Conjuncts,
}
w.UpdateStatus(v.Status())
return w
v = w
}
}
return x

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

if v.status < Finalized && v.state != nil {
v.state.addNotify(c.vertex)
}

return v
}

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

n.doNotify()

if !n.done() {
if len(n.disjunctions) > 0 && v.BaseValue == cycle {
// We disallow entering computations of disjunctions with
Expand Down Expand Up @@ -372,6 +377,23 @@ func (e *Unifier) Unify(c *OpContext, v *Vertex, state VertexStatus) {
}
}

func (n *nodeContext) doNotify() {
if n.errs != nil && len(n.notify) > 0 {
for _, v := range n.notify {
if v.state == nil {
if b, ok := v.BaseValue.(*Bottom); ok {
v.BaseValue = CombineErrors(nil, b, n.errs)
} else {
v.BaseValue = n.errs
}
} else {
v.state.addBottom(n.errs)
}
}
n.notify = n.notify[:0]
}
}

func isStruct(v *Vertex) bool {
_, ok := v.BaseValue.(*StructMarker)
return ok
Expand Down Expand Up @@ -647,6 +669,10 @@ type nodeContext struct {
checks []Validator // BuiltinValidator, other bound values.
errs *Bottom

// notify is used to communicate errors in cyclic dependencies.
// TODO: also use this to communicate increasingly more concrete values.
notify []*Vertex

// Struct information
dynamicFields []envDynamic
ifClauses []envYield
Expand All @@ -671,6 +697,12 @@ type nodeContext struct {
disjunctErrs []*Bottom
}

func (n *nodeContext) addNotify(v *Vertex) {
if v != nil {
n.notify = append(n.notify, v)
}
}

func (n *nodeContext) clone() *nodeContext {
d := n.ctx.Unifier.newNodeContext(n.ctx, n.node)

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

// d.arcMap = append(d.arcMap, n.arcMap...) // XXX add?
d.notify = append(d.notify, n.notify...)
d.checks = append(d.checks, n.checks...)
d.dynamicFields = append(d.dynamicFields, n.dynamicFields...)
d.ifClauses = append(d.ifClauses, n.ifClauses...)
Expand Down

0 comments on commit 008d37d

Please sign in to comment.