Skip to content

Commit 681ec9f

Browse files
committed
internal/core/adt: use explicit hole id
Previously, holes were identified by their closeContext. This worked, but not obviously so. Using explicit hole numbers will make it clearer to see the code is correct and also helps interpreting debugging data. The information is also copied into closeContext for to allow showing it in the graphical debugger. Issue #3635 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: I50b481704af3bbd01c558e6d9b2d981061d25052 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1207168 TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Matthew Sackman <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent f62bb36 commit 681ec9f

File tree

7 files changed

+29
-6
lines changed

7 files changed

+29
-6
lines changed

internal/core/adt/conjunct.go

+4
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,11 @@ func (n *nodeContext) scheduleConjunct(c Conjunct, id CloseInfo) {
202202

203203
// TODO(perf): reuse envDisjunct values so that we can also reuse the
204204
// disjunct slice.
205+
n.ctx.holeID++
205206
d := envDisjunct{
206207
env: env,
207208
cloneID: id,
209+
holeID: n.ctx.holeID,
208210
src: x,
209211
expr: x,
210212
}
@@ -649,9 +651,11 @@ func (n *nodeContext) insertValueConjunct(env *Environment, v Value, id CloseInf
649651
id := id
650652
id.setOptionalV3(n)
651653

654+
n.ctx.holeID++
652655
d := envDisjunct{
653656
env: env,
654657
cloneID: id,
658+
holeID: n.ctx.holeID,
655659
src: x,
656660
value: x,
657661
}

internal/core/adt/context.go

+4
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,10 @@ type OpContext struct {
220220
// encountered. A value of 0 indicates we are not within such field.
221221
optionalMark int
222222

223+
// holdID is a unique identifier for the current "hole", a choice of
224+
// disjunct to be made when processing disjunctions.
225+
holeID int
226+
223227
// inDisjunct indicates that non-monotonic checks should be skipped.
224228
// This is used if we want to do some extra work to eliminate disjunctions
225229
// early. The result of unification should be thrown away if this check is

internal/core/adt/debug.go

+3
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,9 @@ func (m *mermaidContext) pstr(cc *closeContext) string {
623623
// Show the origin of the closeContext.
624624
indentOnNewline(w, 3)
625625
fmt.Fprintf(w, "+%d", cc.depth)
626+
if cc.holeID != 0 {
627+
fmt.Fprintf(w, " H%d", cc.holeID)
628+
}
626629

627630
w.WriteString(close)
628631

internal/core/adt/disjunct.go

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ import (
8787
type envDisjunct struct {
8888
env *Environment
8989
cloneID CloseInfo
90+
holeID int
9091

9192
// fields for new evaluator
9293

internal/core/adt/disjunct2.go

+12-6
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ type disjunct struct {
209209
// is relatively rare, we keep it separate to avoid bloating the closeContext.
210210
type disjunctHole struct {
211211
cc *closeContext
212+
holeID int
212213
underlying *closeContext
213214
}
214215

@@ -228,11 +229,13 @@ func (n *nodeContext) scheduleDisjunction(d envDisjunct) {
228229
// case mergeVertex will override the original value, or multiple disjuncts,
229230
// in which case the original is set to the disjunct itself.
230231
ccHole.incDisjunct(n.ctx, DISJUNCT)
232+
ccHole.holeID = d.holeID
231233

232234
n.disjunctions = append(n.disjunctions, d)
233235

234236
n.disjunctCCs = append(n.disjunctCCs, disjunctHole{
235237
cc: ccHole, // this value is cloned in doDisjunct.
238+
holeID: d.holeID,
236239
underlying: ccHole,
237240
})
238241
}
@@ -291,7 +294,7 @@ func (n *nodeContext) processDisjunctions() *Bottom {
291294
}
292295

293296
// Mark no final in nodeContext and observe later.
294-
results = n.crossProduct(results, cross, d, mode)
297+
results = n.crossProduct(results, cross, d, mode, d.holeID)
295298

296299
// TODO: do we unwind only at the end or also intermittently?
297300
switch len(results) {
@@ -346,7 +349,7 @@ func (n *nodeContext) processDisjunctions() *Bottom {
346349

347350
// crossProduct computes the cross product of the disjuncts of a disjunction
348351
// with an existing set of results.
349-
func (n *nodeContext) crossProduct(dst, cross []*nodeContext, dn *envDisjunct, mode runMode) []*nodeContext {
352+
func (n *nodeContext) crossProduct(dst, cross []*nodeContext, dn *envDisjunct, mode runMode, hole int) []*nodeContext {
350353
defer n.unmarkDepth(n.markDepth())
351354
defer n.unmarkOptional(n.markOptional())
352355

@@ -357,7 +360,7 @@ func (n *nodeContext) crossProduct(dst, cross []*nodeContext, dn *envDisjunct, m
357360

358361
for j, d := range dn.disjuncts {
359362
c := MakeConjunct(dn.env, d.expr, dn.cloneID)
360-
r, err := p.doDisjunct(c, d.mode, mode)
363+
r, err := p.doDisjunct(c, d.mode, mode, hole)
361364

362365
if err != nil {
363366
// TODO: store more error context
@@ -404,7 +407,7 @@ func (n *nodeContext) collectErrors(dn *envDisjunct) (errs *Bottom) {
404407
return b
405408
}
406409

407-
func (n *nodeContext) doDisjunct(c Conjunct, m defaultMode, mode runMode) (*nodeContext, *Bottom) {
410+
func (n *nodeContext) doDisjunct(c Conjunct, m defaultMode, mode runMode, hole int) (*nodeContext, *Bottom) {
408411
if c.CloseInfo.cc == nil {
409412
panic("nil closeContext during init")
410413
}
@@ -426,10 +429,13 @@ func (n *nodeContext) doDisjunct(c Conjunct, m defaultMode, mode runMode) (*node
426429
// a closeContext corresponding to a disjunction always has a parent.
427430
// We therefore do not need to check whether x.parent is nil.
428431
o := oc.allocCC(d.cc)
429-
if c.CloseInfo.cc == d.underlying {
432+
if hole == d.holeID {
430433
ccHole = o
434+
if d.cc.conjunctCount == 0 {
435+
panic("unexpected zero conjunctCount")
436+
}
431437
}
432-
holes = append(holes, disjunctHole{o, d.underlying})
438+
holes = append(holes, disjunctHole{o, d.holeID, d.underlying})
433439
}
434440

435441
if ccHole == nil {

internal/core/adt/fields.go

+4
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ type closeContext struct {
170170
// in disjunction overlays. This is mostly for debugging.
171171
generation int
172172

173+
// a non-zero value indicates that the closeContext is part of a disjunction
174+
// and that it is associated with the given Hole Index.
175+
holeID int
176+
173177
dependencies []*ccDep // For testing only. See debug.go
174178

175179
// externalDeps lists the closeContexts associated with a root node for

internal/core/adt/overlay.go

+1
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ func (ctx *overlayContext) allocCC(cc *closeContext) *closeContext {
270270
o := &closeContext{generation: ctx.generation}
271271
cc.overlay = o
272272
o.depth = cc.depth
273+
o.holeID = cc.holeID
273274

274275
if cc.parent != nil {
275276
o.parent = ctx.allocCC(cc.parent)

0 commit comments

Comments
 (0)