Skip to content

Commit 831374c

Browse files
committed
internal/core/adt: clean up indirects and mark disjuncts
Vertex.BaseValue may point to another Vertex. There are now three kinds of vertices that this value may point to: - computed, external results, like from builtins. - disjuncts resulting from resolved disjunctions - structure shared nodes The old evaluator only had the first. When accessing the actual value of a Vertex, one should dereference the pointers. However, there is lots of interesting meta information that one may want to access, i.e. the original path and the original full disjunction expression. The new evaluator should therefore be more careful as to when something is dereferenced. In this CL, we introduce a means to identify whether a Vertex was the result of a disjunction. We adjust various Indirect calls by removing them or replacing them with more fine-grained versions. This should be a no-op change. Various points where indirect have been tightened to dereference only the kinds of vertices that should be dereferenced. The idea is to do a bunch of such changes in separate CLs to allow bisecting to specific changes if there are any issues. We rename the new "Indirect*" functions to "Deref*", which is a more accurate term. This also allows us to visually inspect if we have considered all call sites. We will rename and inspect Indirect in a separate CL. Issue #2854 Issue #2851 Issue #2884 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: I659d075f61aa7f96db99a504c31bd658c54ee58b Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1193844 Unity-Result: CUE porcuepine <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Daniel Martí <[email protected]>
1 parent 382e4be commit 831374c

File tree

7 files changed

+45
-10
lines changed

7 files changed

+45
-10
lines changed

cue/types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ func (i *Iterator) Next() bool {
235235
p := linkParent(i.val.parent_, i.val.v, arc)
236236
i.f = arc.Label
237237
i.arcType = arc.ArcType
238+
// TODO: this should not indirect disjunctions, as this will cause losing
239+
// information, which is now available in the new evaluator. Find a safe
240+
// way to preserve disjunction information while keeping backward
241+
// compatibility in the API.
238242
arc = arc.Indirect()
239243
i.cur = makeValue(i.val.idx, arc, p)
240244
i.p++

internal/core/adt/composite.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ type Vertex struct {
206206
// hasPendingArc is set if this Vertex has a void arc (e.g. for comprehensions)
207207
hasPendingArc bool
208208

209+
// IsDisjunct indicates this Vertex is a disjunct resulting from a
210+
// disjunction evaluation.
211+
IsDisjunct bool
212+
209213
// ArcType indicates the level of optionality of this arc.
210214
ArcType ArcType
211215

internal/core/adt/context.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,9 @@ func (c *OpContext) resolveState(x Conjunct, r Resolver, state combinedFlags) (*
496496
return nil, arc.ChildErrors
497497
}
498498

499-
arc = arc.Indirect()
499+
if !c.isDevVersion() {
500+
arc = arc.Indirect()
501+
}
500502

501503
return arc, err
502504
}
@@ -707,8 +709,9 @@ func (c *OpContext) evalState(v Expr, state combinedFlags) (result Value) {
707709
return nil
708710
}
709711
// TODO: consider moving this after markCycle, depending on how we
710-
// implement markCycle.
711-
arc = arc.Indirect()
712+
// implement markCycle, or whether we need it at all.
713+
// TODO: is this indirect necessary?
714+
// arc = arc.Indirect()
712715

713716
// Save the old CloseInfo and restore after evaluate to avoid detecting
714717
// spurious cycles.
@@ -834,8 +837,9 @@ func (c *OpContext) unifyNode(v Expr, state combinedFlags) (result Value) {
834837
return nil
835838
}
836839
// TODO: consider moving this after markCycle, depending on how we
837-
// implement markCycle.
838-
v = v.Indirect()
840+
// implement markCycle, or whether we need it at all.
841+
// TODO: is this indirect necessary?
842+
// v = v.Indirect()
839843

840844
if c.isDevVersion() {
841845
if n := v.getState(c); n != nil {

internal/core/adt/overlay.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ type overlayContext struct {
7979
func (ctx *overlayContext) cloneRoot(root *nodeContext) *nodeContext {
8080
// Clone all vertices that need to be cloned to support the overlay.
8181
v := ctx.cloneVertex(root.node)
82+
v.IsDisjunct = true
8283

8384
// TODO: patch notifications to any node that is within the disjunct to
8485
// point to the new vertex instead.

internal/core/adt/share.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,32 @@ func (n *nodeContext) shareIfPossible(c Conjunct, arc *Vertex, id CloseInfo) boo
104104
return true
105105
}
106106

107-
// IndirectNonShared finds the indirection of an arc that is not the result of
107+
// DerefDisjunct indirects a node that points to a disjunction.
108+
func (v *Vertex) DerefDisjunct() *Vertex {
109+
for {
110+
arc, ok := v.BaseValue.(*Vertex)
111+
if !ok || !arc.IsDisjunct {
112+
return v
113+
}
114+
v = arc
115+
}
116+
}
117+
118+
// DerefNonDisjunct indirects a node that points to a disjunction.
119+
func (v *Vertex) DerefNonDisjunct() *Vertex {
120+
for {
121+
arc, ok := v.BaseValue.(*Vertex)
122+
if !ok || arc.IsDisjunct {
123+
return v
124+
}
125+
v = arc
126+
}
127+
}
128+
129+
// DerefNonShared finds the indirection of an arc that is not the result of
108130
// structure sharing. This is especially relevant when indirecting disjunction
109131
// values.
110-
func (v *Vertex) IndirectNonShared() *Vertex {
132+
func (v *Vertex) DerefNonShared() *Vertex {
111133
if v.state != nil && v.state.isShared {
112134
return v
113135
}

internal/core/adt/tasks.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,11 @@ func processResolver(ctx *OpContext, t *task, mode runMode) {
103103
}
104104
ctx.Logf(t.node.node, "RESOLVED %v to %v %v", r, arc.Label, fmt.Sprintf("%p", arc))
105105
// TODO: consider moving after markCycle or removing.
106-
arc = arc.Indirect()
106+
d := arc.DerefDisjunct()
107107

108108
// A reference that points to itself indicates equality. In that case
109109
// we are done computing and we can return the arc as is.
110-
ci, skip := t.node.markCycle(arc, t.env, r, t.id)
110+
ci, skip := t.node.markCycle(d, t.env, r, t.id)
111111
if skip {
112112
return
113113
}

internal/core/adt/unify.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func (v *Vertex) unify(c *OpContext, needs condition, mode runMode) bool {
160160

161161
defer c.PopArc(c.PushArc(v))
162162

163-
w := v.IndirectNonShared() // Dereference the disjunction result.
163+
w := v.DerefNonShared() // Dereference the disjunction result.
164164
if w != v {
165165
if w.Closed {
166166
// Should resolve with dereference.

0 commit comments

Comments
 (0)