internal/core: move CloseID from Environment to Conjunct

Change-Id: If83db9714764e30c764c8947cfb3936beafd8bc5
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7001
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
diff --git a/internal/core/eval/eval.go b/internal/core/eval/eval.go
index 647d4b8..bc5a477 100644
--- a/internal/core/eval/eval.go
+++ b/internal/core/eval/eval.go
@@ -112,12 +112,12 @@
 type Evaluator struct {
 	r       adt.Runtime
 	index   adt.StringIndexer
-	closeID uint32
+	closeID adt.ID
 
 	stats Stats
 }
 
-func (e *Evaluator) nextID() uint32 {
+func (e *Evaluator) nextID() adt.ID {
 	e.closeID++
 	return e.closeID
 }
@@ -363,16 +363,10 @@
 			isFinal: true,
 		}
 
-		closeID := uint32(0)
-
 		for _, x := range v.Conjuncts {
-			closeID := closeID
 			// TODO: needed for reentrancy. Investigate usefulness for cycle
 			// detection.
-			if x.Env != nil && x.Env.CloseID != 0 {
-				closeID = x.Env.CloseID
-			}
-			n.addExprConjunct(x, closeID, true)
+			n.addExprConjunct(x, true)
 		}
 
 		if i == 0 {
@@ -577,20 +571,20 @@
 
 	replace := n.replace
 	if replace == nil {
-		replace = map[uint32]*CloseDef{}
+		replace = map[adt.ID]*CloseDef{}
 	}
 
 	// Mark any used CloseID to keep, if not already replaced.
 	for _, x := range n.optionals {
-		if _, ok := replace[x.env.CloseID]; !ok {
-			replace[x.env.CloseID] = nil
+		if _, ok := replace[x.id]; !ok {
+			replace[x.id] = nil
 		}
 	}
 	for _, a := range n.node.Arcs {
 		for _, c := range a.Conjuncts {
 			if c.Env != nil {
-				if _, ok := replace[c.Env.CloseID]; !ok {
-					replace[c.Env.CloseID] = nil
+				if _, ok := replace[c.ID()]; !ok {
+					replace[c.ID()] = nil
 				}
 			}
 		}
@@ -753,8 +747,8 @@
 	aStruct   adt.Expr
 	hasTop    bool
 	newClose  *CloseDef
-	// closeID   uint32 // from parent, or if not exist, new if introducing a def.
-	replace map[uint32]*CloseDef
+	// closeID   adt.ID // from parent, or if not exist, new if introducing a def.
+	replace map[adt.ID]*CloseDef
 
 	// Expression conjuncts
 	lists  []envList
@@ -891,18 +885,19 @@
 
 type conjunct struct {
 	adt.Conjunct
-	closeID uint32
-	top     bool
+	top bool
 }
 
 type envDynamic struct {
 	env   *adt.Environment
 	field *adt.DynamicField
+	id    adt.ID
 }
 
 type envYield struct {
 	env   *adt.Environment
 	yield adt.Yielder
+	id    adt.ID
 }
 
 type envList struct {
@@ -910,6 +905,7 @@
 	list    *adt.ListLit
 	n       int64 // recorded length after evaluator
 	elipsis *adt.Ellipsis
+	id      adt.ID
 }
 
 func (n *nodeContext) addBottom(b *adt.Bottom) {
@@ -927,52 +923,51 @@
 // addExprConjuncts will attempt to evaluate an adt.Expr and insert the value
 // into the nodeContext if successful or queue it for later evaluation if it is
 // incomplete or is not value.
-func (n *nodeContext) addExprConjunct(v adt.Conjunct, def uint32, top bool) {
+func (n *nodeContext) addExprConjunct(v adt.Conjunct, top bool) {
 	env := v.Env
-	if env != nil && env.CloseID != def {
-		e := *env
-		e.CloseID = def
-		env = &e
-	}
+	id := v.CloseID
+
 	switch x := v.Expr().(type) {
 	case adt.Value:
-		n.addValueConjunct(env, x)
+		n.addValueConjunct(env, x, id)
 
 	case *adt.BinaryExpr:
 		if x.Op == adt.AndOp {
-			n.addExprConjunct(adt.MakeConjunct(env, x.X), def, false)
-			n.addExprConjunct(adt.MakeConjunct(env, x.Y), def, false)
+			n.addExprConjunct(adt.MakeConjunct(env, x.X, id), false)
+			n.addExprConjunct(adt.MakeConjunct(env, x.Y, id), false)
 		} else {
-			n.evalExpr(v, def, top)
+			n.evalExpr(v, top)
 		}
 
 	case *adt.StructLit:
-		n.addStruct(env, x, def, top)
+		n.addStruct(env, x, id, top)
 
 	case *adt.ListLit:
-		n.lists = append(n.lists, envList{env: env, list: x})
+		n.lists = append(n.lists, envList{env: env, list: x, id: id})
 
 	case *adt.DisjunctionExpr:
 		if n.disjunctions != nil {
 			_ = n.disjunctions
 		}
-		n.addDisjunction(env, x, def, top)
+		n.addDisjunction(env, x, id, top)
 
 	default:
 		// Must be Resolver or Evaluator.
-		n.evalExpr(v, def, top)
+		n.evalExpr(v, top)
 	}
 
 	if top {
-		n.updateReplace(v.Env)
+		n.updateReplace(v.CloseID)
 	}
 }
 
 // evalExpr is only called by addExprConjunct.
-func (n *nodeContext) evalExpr(v adt.Conjunct, closeID uint32, top bool) {
+func (n *nodeContext) evalExpr(v adt.Conjunct, top bool) {
 	// Require an Environment.
 	ctx := n.ctx
 
+	closeID := v.CloseID
+
 	// TODO: see if we can do without these counters.
 	for _, d := range v.Env.Deref {
 		d.EvalCount++
@@ -1002,7 +997,7 @@
 			}
 		}
 		if arc == nil {
-			n.exprs = append(n.exprs, conjunct{v, closeID, top})
+			n.exprs = append(n.exprs, conjunct{v, top})
 			break
 		}
 
@@ -1074,8 +1069,10 @@
 			id := n.eval.nextID()
 			n.insertClosed(arc, id, cyclic, arc)
 		} else {
-			for _, a := range arc.Conjuncts {
-				n.addExprConjunct(updateCyclic(a, cyclic, arc), closeID, top)
+			for _, c := range arc.Conjuncts {
+				c = updateCyclic(c, cyclic, arc)
+				c.CloseID = closeID
+				n.addExprConjunct(c, top)
 			}
 		}
 
@@ -1084,7 +1081,7 @@
 		// Could be unify?
 		val, complete := ctx.Evaluate(v.Env, v.Expr())
 		if !complete {
-			n.exprs = append(n.exprs, conjunct{v, closeID, top})
+			n.exprs = append(n.exprs, conjunct{v, top})
 			break
 		}
 
@@ -1094,14 +1091,15 @@
 			b, ok := v.Value.(*adt.Bottom)
 			if ok && b.IsIncomplete() && len(v.Conjuncts) > 0 {
 				for _, c := range v.Conjuncts {
-					n.addExprConjunct(c, closeID, top)
+					c.CloseID = closeID
+					n.addExprConjunct(c, top)
 				}
 				break
 			}
 		}
 
 		// TODO: insert in vertex as well
-		n.addValueConjunct(v.Env, val)
+		n.addValueConjunct(v.Env, val, closeID)
 
 	default:
 		panic(fmt.Sprintf("unknown expression of type %T", x))
@@ -1138,17 +1136,19 @@
 		env.Deref = append(env.Deref, deref)
 		env.Cycles = append(env.Cycles, deref)
 	}
-	return adt.MakeConjunct(env, c.Expr())
+	return adt.MakeConjunct(env, c.Expr(), c.CloseID)
 }
 
-func (n *nodeContext) insertClosed(arc *adt.Vertex, id uint32, cyclic bool, deref *adt.Vertex) {
+func (n *nodeContext) insertClosed(arc *adt.Vertex, id adt.ID, cyclic bool, deref *adt.Vertex) {
 	n.needClose = true
 
 	current := n.newClose
 	n.newClose = nil
 
-	for _, a := range arc.Conjuncts {
-		n.addExprConjunct(updateCyclic(a, cyclic, deref), id, false)
+	for _, c := range arc.Conjuncts {
+		c = updateCyclic(c, cyclic, deref)
+		c.CloseID = id
+		n.addExprConjunct(c, false)
 	}
 
 	current, n.newClose = n.newClose, current
@@ -1159,7 +1159,7 @@
 	n.addAnd(current)
 }
 
-func (n *nodeContext) addValueConjunct(env *adt.Environment, v adt.Value) {
+func (n *nodeContext) addValueConjunct(env *adt.Environment, v adt.Value, id adt.ID) {
 	n.updateCyclicStatus(env)
 
 	if x, ok := v.(*adt.Vertex); ok {
@@ -1181,11 +1181,13 @@
 		if !x.IsData() && len(x.Conjuncts) > 0 {
 			cyclic := env != nil && env.Cyclic
 			if needClose {
-				n.insertClosed(x, env.CloseID, cyclic, nil)
+				n.insertClosed(x, id, cyclic, nil)
 				return
 			}
 			for _, c := range x.Conjuncts {
-				n.addExprConjunct(updateCyclic(c, cyclic, nil), 0, false) // TODO: Pass from eval
+				c = updateCyclic(c, cyclic, nil)
+				c.CloseID = id
+				n.addExprConjunct(c, false) // TODO: Pass from eval
 			}
 			return
 		}
@@ -1206,17 +1208,17 @@
 					n.aStruct = x
 				}
 				// TODO, insert here as
-				n.insertField(a.Label, adt.MakeConjunct(nil, a))
+				n.insertField(a.Label, adt.MakeConjunct(nil, a, id))
 				// sub, _ := n.node.GetArc(a.Label)
 				// sub.Add(a)
 			}
 
 		default:
-			n.addValueConjunct(env, v)
+			n.addValueConjunct(env, v, id)
 
 			for _, a := range x.Arcs {
 				// TODO(errors): report error when this is a regular field.
-				n.insertField(a.Label, adt.MakeConjunct(nil, a))
+				n.insertField(a.Label, adt.MakeConjunct(nil, a, id))
 				// sub, _ := n.node.GetArc(a.Label)
 				// sub.Add(a)
 			}
@@ -1239,17 +1241,17 @@
 
 	switch x := v.(type) {
 	case *adt.Disjunction:
-		n.addDisjunctionValue(env, x, 0, true)
+		n.addDisjunctionValue(env, x, id, true)
 
 	case *adt.Conjunction:
 		for _, x := range x.Values {
-			n.addValueConjunct(env, x)
+			n.addValueConjunct(env, x, id)
 		}
 
 	case *adt.Top:
 		n.hasTop = true
 		// TODO: Is this correct. Needed for elipsis, but not sure for others.
-		n.optionals = append(n.optionals, fieldSet{env: env, isOpen: true})
+		n.optionals = append(n.optionals, fieldSet{env: env, id: id, isOpen: true})
 
 	case *adt.BasicType:
 		// handled above
@@ -1259,7 +1261,7 @@
 		case adt.LessThanOp, adt.LessEqualOp:
 			if y := n.upperBound; y != nil {
 				n.upperBound = nil
-				n.addValueConjunct(env, adt.SimplifyBounds(ctx, n.kind, x, y))
+				n.addValueConjunct(env, adt.SimplifyBounds(ctx, n.kind, x, y), id)
 				return
 			}
 			n.upperBound = x
@@ -1267,7 +1269,7 @@
 		case adt.GreaterThanOp, adt.GreaterEqualOp:
 			if y := n.lowerBound; y != nil {
 				n.lowerBound = nil
-				n.addValueConjunct(env, adt.SimplifyBounds(ctx, n.kind, x, y))
+				n.addValueConjunct(env, adt.SimplifyBounds(ctx, n.kind, x, y), id)
 				return
 			}
 			n.lowerBound = x
@@ -1303,7 +1305,7 @@
 		if u := adt.SimplifyBounds(ctx, n.kind, n.lowerBound, n.upperBound); u != nil {
 			n.lowerBound = nil
 			n.upperBound = nil
-			n.addValueConjunct(env, u)
+			n.addValueConjunct(env, u, id)
 		}
 	}
 }
@@ -1318,7 +1320,7 @@
 func (n *nodeContext) addStruct(
 	env *adt.Environment,
 	s *adt.StructLit,
-	newDef uint32,
+	closeID adt.ID,
 	top bool) {
 
 	n.updateCyclicStatus(env) // to handle empty structs.
@@ -1326,12 +1328,6 @@
 	ctx := n.ctx
 	n.node.AddStructs(s)
 
-	// Inherit closeID from environment, unless this is a new definition.
-	closeID := newDef
-	if closeID == 0 && env != nil {
-		closeID = env.CloseID
-	}
-
 	// NOTE: This is a crucial point in the code:
 	// Unification derferencing happens here. The child nodes are set to
 	// an Environment linked to the current node. Together with the De Bruijn
@@ -1345,9 +1341,8 @@
 	// 	}
 	// }
 	childEnv := &adt.Environment{
-		Up:      env,
-		Vertex:  n.node,
-		CloseID: closeID,
+		Up:     env,
+		Vertex: n.node,
 	}
 	if env != nil {
 		childEnv.Cyclic = env.Cyclic
@@ -1357,7 +1352,7 @@
 	var hasOther, hasBulk adt.Node
 	hasEmbed := false
 
-	opt := fieldSet{pos: s, env: childEnv}
+	opt := fieldSet{pos: s, env: childEnv, id: closeID}
 
 	for _, d := range s.Decls {
 		switch x := d.(type) {
@@ -1374,16 +1369,16 @@
 		case *adt.DynamicField:
 			n.aStruct = s
 			hasOther = x
-			n.dynamicFields = append(n.dynamicFields, envDynamic{childEnv, x})
+			n.dynamicFields = append(n.dynamicFields, envDynamic{childEnv, x, closeID})
 			opt.AddDynamic(ctx, childEnv, x)
 
 		case *adt.ForClause:
 			hasOther = x
-			n.forClauses = append(n.forClauses, envYield{childEnv, x})
+			n.forClauses = append(n.forClauses, envYield{childEnv, x, closeID})
 
 		case adt.Yielder:
 			hasOther = x
-			n.ifClauses = append(n.ifClauses, envYield{childEnv, x})
+			n.ifClauses = append(n.ifClauses, envYield{childEnv, x, closeID})
 
 		case adt.Expr:
 			hasEmbed = true
@@ -1395,7 +1390,7 @@
 			n.newClose = nil
 
 			hasOther = x
-			n.addExprConjunct(adt.MakeConjunct(childEnv, x), id, false)
+			n.addExprConjunct(adt.MakeConjunct(childEnv, x, id), false)
 
 			current, n.newClose = n.newClose, current
 
@@ -1443,7 +1438,7 @@
 			if x.Label.IsString() {
 				n.aStruct = s
 			}
-			n.insertField(x.Label, adt.MakeConjunct(childEnv, x))
+			n.insertField(x.Label, adt.MakeConjunct(childEnv, x, closeID))
 		}
 	}
 }
@@ -1502,7 +1497,7 @@
 	exprs := n.exprs
 	n.exprs = n.exprs[:0]
 	for _, x := range exprs {
-		n.addExprConjunct(x.Conjunct, x.closeID, x.top)
+		n.addExprConjunct(x.Conjunct, x.top)
 
 		// collect and and or
 	}
@@ -1530,11 +1525,11 @@
 			continue
 		}
 		if b, _ := v.(*adt.Bottom); b != nil {
-			n.addValueConjunct(nil, b)
+			n.addValueConjunct(nil, b, d.id)
 			continue
 		}
 		f = ctx.Label(v)
-		n.insertField(f, adt.MakeConjunct(d.env, d.field))
+		n.insertField(f, adt.MakeConjunct(d.env, d.field, d.id))
 	}
 
 	progress = k < len(n.dynamicFields)
@@ -1575,7 +1570,7 @@
 		}
 
 		for _, st := range sa {
-			n.addStruct(st.env, st.s, 0, true)
+			n.addStruct(st.env, st.s, d.id, true)
 		}
 	}
 
@@ -1639,7 +1634,7 @@
 
 		for _, a := range elems {
 			if a.Conjuncts == nil {
-				n.insertField(a.Label, adt.MakeConjunct(nil, a.Value))
+				n.insertField(a.Label, adt.MakeConjunct(nil, a.Value, 0))
 				continue
 			}
 			for _, c := range a.Conjuncts {
@@ -1663,7 +1658,7 @@
 					label, err := adt.MakeLabel(x.Source(), index, adt.IntLabel)
 					n.addErr(err)
 					index++
-					n.insertField(label, adt.MakeConjunct(e, st))
+					n.insertField(label, adt.MakeConjunct(e, st, l.id))
 				})
 				hasComprehension = true
 				if err != nil && !err.IsIncomplete() {
@@ -1681,7 +1676,7 @@
 				label, err := adt.MakeLabel(x.Source(), index, adt.IntLabel)
 				n.addErr(err)
 				index++ // TODO: don't use insertField.
-				n.insertField(label, adt.MakeConjunct(l.env, x))
+				n.insertField(label, adt.MakeConjunct(l.env, x, l.id))
 			}
 
 			// Terminate early n case of runaway comprehension.
@@ -1734,7 +1729,7 @@
 			continue
 		}
 
-		f := fieldSet{pos: l.list, env: l.env}
+		f := fieldSet{pos: l.list, env: l.env, id: l.id}
 		f.AddEllipsis(c, l.elipsis)
 
 		n.optionals = append(n.optionals, f)