internal/core/adt: more merging of adt and former eval

Next phase to remove adt.Unifier, which is now redundant.

Change-Id: I2d83e56134a4ba7fbcef1d4365f4b05cb028b0ea
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/8322
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
diff --git a/cue/types.go b/cue/types.go
index bf3a10d..88e5660 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -2298,10 +2298,9 @@
 					a.AddConjunct(adt.MakeRootConjunct(env, n.Val))
 					b.AddConjunct(adt.MakeRootConjunct(env, disjunct.Val))
 
-					e := eval.New(v.idx.Runtime)
-					ctx := e.NewContext(nil)
-					e.Unify(ctx, &a, adt.Finalized)
-					e.Unify(ctx, &b, adt.Finalized)
+					ctx := eval.NewContext(v.idx.Runtime, nil)
+					ctx.Unify(&a, adt.Finalized)
+					ctx.Unify(&b, adt.Finalized)
 					if allowed(ctx, v.v, &b) != nil {
 						// Everything subsumed bottom
 						continue outerExpr
diff --git a/internal/core/adt/composite.go b/internal/core/adt/composite.go
index 4ffc567..143df54 100644
--- a/internal/core/adt/composite.go
+++ b/internal/core/adt/composite.go
@@ -411,7 +411,7 @@
 }
 
 func (v *Vertex) Err(c *OpContext, state VertexStatus) *Bottom {
-	c.Unify(c, v, state)
+	c.Unify(v, state)
 	if b, ok := v.BaseValue.(*Bottom); ok {
 		return b
 	}
@@ -421,7 +421,7 @@
 // func (v *Vertex) Evaluate()
 
 func (v *Vertex) Finalize(c *OpContext) {
-	c.Unify(c, v, Finalized)
+	c.Unify(v, Finalized)
 }
 
 func (v *Vertex) AddErr(ctx *OpContext, b *Bottom) {
diff --git a/internal/core/adt/context.go b/internal/core/adt/context.go
index 443fc90..de18cb0 100644
--- a/internal/core/adt/context.go
+++ b/internal/core/adt/context.go
@@ -137,10 +137,7 @@
 	ctx := &OpContext{
 		Runtime: cfg.Runtime,
 		Format:  cfg.Format,
-		Unifier: Unifier{
-			r: cfg.Runtime,
-		},
-		vertex: v,
+		vertex:  v,
 	}
 	if v != nil {
 		ctx.e = &Environment{Up: nil, Vertex: v}
@@ -148,13 +145,17 @@
 	return ctx
 }
 
-// An OpContext associates a Runtime and Unifier to allow evaluating the types
-// defined in this package. It tracks errors provides convenience methods for
-// evaluating values.
+// An OpContext implements CUE's unification operation. It's operations only
+// operation on values that are created with the Runtime with which an OpContext
+// is associated. An OpContext is not goroutine save and only one goroutine may
+// use an OpContext at a time.
+//
 type OpContext struct {
 	Runtime
 	Format func(Node) string
-	Unifier
+
+	stats        Stats
+	freeListNode *nodeContext
 
 	e         *Environment
 	src       ast.Node
@@ -253,7 +254,7 @@
 	for ; upCount > 0; upCount-- {
 		e = e.Up
 	}
-	c.Unify(c, e.Vertex, Partial)
+	c.Unify(e.Vertex, Partial)
 	return e.Vertex
 }
 
@@ -342,7 +343,7 @@
 	case *Bottom:
 		return x
 	case *Vertex:
-		v := c.Unifier.Evaluate(c, x)
+		v := c.evaluate(x, Partial)
 		if b, ok := v.(*Bottom); ok {
 			return b
 		}
@@ -591,7 +592,7 @@
 			return nil
 		}
 
-		v := c.Unifier.evaluate(c, arc, state)
+		v := c.evaluate(arc, state)
 		return v
 
 	default:
@@ -646,7 +647,7 @@
 
 		if v.BaseValue == nil || v.BaseValue == cycle {
 			// Use node itself to allow for cycle detection.
-			c.Unifier.Unify(c, v, state)
+			c.Unify(v, state)
 		}
 
 		if b, _ := v.BaseValue.(*Bottom); b != nil && b.Code != IncompleteError {
@@ -1134,6 +1135,6 @@
 	for _, x := range values {
 		list.Elems = append(list.Elems, x)
 	}
-	c.Unify(c, v, Finalized)
+	c.Unify(v, Finalized)
 	return v
 }
diff --git a/internal/core/adt/eval.go b/internal/core/adt/eval.go
index f873cf1..e42a930 100644
--- a/internal/core/adt/eval.go
+++ b/internal/core/adt/eval.go
@@ -43,10 +43,6 @@
 // - Test closedness far more thoroughly.
 //
 
-func NewUnifier(r Runtime) *Unifier {
-	return &Unifier{r: r, index: r}
-}
-
 type Stats struct {
 	DisjunctCount int
 	UnifyCount    int
@@ -83,8 +79,8 @@
 	return buf.String()
 }
 
-func (e *Unifier) Stats() *Stats {
-	return &e.stats
+func (c *OpContext) Stats() *Stats {
+	return &c.stats
 }
 
 // TODO: Note: NewContext takes essentially a cue.Value. By making this
@@ -102,33 +98,7 @@
 	Err:  errors.Newf(token.NoPos, "incomplete"),
 }
 
-// A Unifier implements a strategy for CUE's unification operation. It must
-// handle the following aspects of CUE evaluation:
-//
-//    - Structural and reference cycles
-//    - Non-monotic validation
-//    - Fixed-point computation of comprehension
-//
-type Unifier struct {
-	r     Runtime
-	index StringIndexer
-
-	stats Stats
-
-	freeListNode *nodeContext
-}
-
-func (e *Unifier) Eval(v *Vertex) errors.Error {
-	if v.BaseValue == nil {
-		ctx := NewContext(e.r, v)
-		e.Unify(ctx, v, Partial)
-	}
-
-	// extract error if needed.
-	return nil
-}
-
-// Evaluate returns the evaluated value associated with v. It may return a
+// evaluate returns the evaluated value associated with v. It may return a
 // partial result. That is, if v was not yet unified, it may return a
 // concrete value that must be the result assuming the configuration has no
 // errors.
@@ -140,14 +110,10 @@
 // error.
 //
 // TODO: return *Vertex
-func (e *Unifier) Evaluate(c *OpContext, v *Vertex) Value {
-	return e.evaluate(c, v, Partial)
-}
-
-func (e *Unifier) evaluate(c *OpContext, v *Vertex, state VertexStatus) Value {
+func (c *OpContext) evaluate(v *Vertex, state VertexStatus) Value {
 	if v.BaseValue == nil || v.BaseValue == cycle {
 		// Use node itself to allow for cycle detection.
-		e.Unify(c, v, state)
+		c.Unify(v, state)
 	}
 
 	if n := v.state; n != nil {
@@ -186,9 +152,9 @@
 }
 
 // Unify fully unifies all values of a Vertex to completion and stores
-// the result in the Vertex. If Unify was called on v before it returns
+// the result in the Vertex. If unify was called on v before it returns
 // the cached results.
-func (e *Unifier) Unify(c *OpContext, v *Vertex, state VertexStatus) {
+func (c *OpContext) Unify(v *Vertex, state VertexStatus) {
 	// defer c.PopVertex(c.PushVertex(v))
 
 	// Ensure a node will always have a nodeContext after calling Unify if it is
@@ -254,7 +220,7 @@
 
 		defer c.PopArc(c.PushArc(v))
 
-		e.stats.UnifyCount++
+		c.stats.UnifyCount++
 
 		// Clear any remaining error.
 		if err := c.Err(); err != nil {
@@ -436,7 +402,7 @@
 		for n.maybeSetCache(); n.expandOne(); n.maybeSetCache() {
 		}
 
-		if aList, id := n.addLists(ctx); aList != nil {
+		if aList, id := n.addLists(); aList != nil {
 			n.updateNodeType(ListKind, aList, id)
 		} else {
 			break
@@ -612,7 +578,7 @@
 			// Call UpdateStatus here to be absolutely sure the status is set
 			// correctly and that we are not regressing.
 			n.node.UpdateStatus(EvaluatingArcs)
-			n.ctx.Unifier.Unify(ctx, a, state)
+			ctx.Unify(a, state)
 			// Don't set the state to Finalized if the child arcs are not done.
 			if state == Finalized && a.status < Finalized {
 				state = AllArcs
@@ -742,7 +708,7 @@
 }
 
 func (n *nodeContext) clone() *nodeContext {
-	d := n.ctx.Unifier.newNodeContext(n.ctx, n.node)
+	d := n.ctx.newNodeContext(n.node)
 
 	d.refCount++
 
@@ -779,13 +745,13 @@
 	return d
 }
 
-func (e *Unifier) newNodeContext(ctx *OpContext, node *Vertex) *nodeContext {
-	if n := e.freeListNode; n != nil {
-		e.stats.Reused++
-		e.freeListNode = n.nextFree
+func (c *OpContext) newNodeContext(node *Vertex) *nodeContext {
+	if n := c.freeListNode; n != nil {
+		c.stats.Reused++
+		c.freeListNode = n.nextFree
 
 		*n = nodeContext{
-			ctx:           ctx,
+			ctx:           c,
 			node:          node,
 			kind:          TopKind,
 			arcMap:        n.arcMap[:0],
@@ -805,10 +771,10 @@
 
 		return n
 	}
-	e.stats.Allocs++
+	c.stats.Allocs++
 
 	return &nodeContext{
-		ctx:  ctx,
+		ctx:  c,
 		node: node,
 		kind: TopKind,
 	}
@@ -819,7 +785,7 @@
 		if v.status == Finalized {
 			return nil
 		}
-		v.state = c.Unifier.newNodeContext(c, v)
+		v.state = c.newNodeContext(v)
 	} else if v.state.node != v {
 		panic("getNodeContext: nodeContext out of sync")
 	}
@@ -841,7 +807,7 @@
 		if v.status == Finalized {
 			v.freeNodeState()
 		} else {
-			n.ctx.Unifier.stats.Retained++
+			n.ctx.stats.Retained++
 		}
 	}
 }
@@ -853,19 +819,19 @@
 	state := v.state
 	v.state = nil
 
-	state.ctx.Unifier.freeNodeContext(state)
+	state.ctx.freeNodeContext(state)
 }
 
 func (n *nodeContext) free() {
 	if n.refCount--; n.refCount == 0 {
-		n.ctx.Unifier.freeNodeContext(n)
+		n.ctx.freeNodeContext(n)
 	}
 }
 
-func (e *Unifier) freeNodeContext(n *nodeContext) {
-	e.stats.Freed++
-	n.nextFree = e.freeListNode
-	e.freeListNode = n
+func (c *OpContext) freeNodeContext(n *nodeContext) {
+	c.stats.Freed++
+	n.nextFree = c.freeListNode
+	c.freeListNode = n
 	n.node = nil
 	n.refCount = 0
 }
@@ -1869,7 +1835,7 @@
 //
 // TODO(embeddedScalars): for embedded scalars, there should be another pass
 // of evaluation expressions after expanding lists.
-func (n *nodeContext) addLists(c *OpContext) (oneOfTheLists Expr, anID CloseInfo) {
+func (n *nodeContext) addLists() (oneOfTheLists Expr, anID CloseInfo) {
 	if len(n.lists) == 0 && len(n.vLists) == 0 {
 		return nil, CloseInfo{}
 	}
@@ -1883,6 +1849,8 @@
 		max = len(n.node.Arcs)
 	}
 
+	c := n.ctx
+
 	for _, l := range n.vLists {
 		oneOfTheLists = l
 
diff --git a/internal/core/adt/expr.go b/internal/core/adt/expr.go
index 494199e..00a871e 100644
--- a/internal/core/adt/expr.go
+++ b/internal/core/adt/expr.go
@@ -79,7 +79,7 @@
 	// used in a context where more conjuncts are added. It may also lead
 	// to disjuncts being in a partially expanded state, leading to
 	// misaligned nodeContexts.
-	c.Unifier.Unify(c, v, AllArcs)
+	c.Unify(v, AllArcs)
 	return v
 }
 
@@ -287,7 +287,7 @@
 	e := c.Env(0)
 	v := &Vertex{Conjuncts: []Conjunct{{e, x, CloseInfo{}}}}
 	// TODO: should be AllArcs and then use Finalize for builtins?
-	c.Unifier.Unify(c, v, Finalized) // TODO: also partial okay?
+	c.Unify(v, Finalized) // TODO: also partial okay?
 	return v
 }
 
@@ -961,7 +961,7 @@
 	if x.Op == AndOp {
 		// Anonymous Arc
 		v := &Vertex{Conjuncts: []Conjunct{{env, x, CloseInfo{}}}}
-		c.Unifier.Unify(c, v, Finalized)
+		c.Unify(v, Finalized)
 		return v
 	}
 
@@ -1189,7 +1189,7 @@
 			env := c.Env(0)
 			x := &BinaryExpr{Op: AndOp, X: v, Y: a}
 			n := &Vertex{Conjuncts: []Conjunct{{env, x, CloseInfo{}}}}
-			c.Unifier.Unify(c, n, Finalized)
+			c.Unify(n, Finalized)
 			if _, ok := n.BaseValue.(*Bottom); ok {
 				c.addErrf(0, pos(a),
 					"cannot use %s as %s in argument %d to %s",
@@ -1314,7 +1314,7 @@
 func (x *DisjunctionExpr) evaluate(c *OpContext) Value {
 	e := c.Env(0)
 	v := &Vertex{Conjuncts: []Conjunct{{e, x, CloseInfo{}}}}
-	c.Unifier.Unify(c, v, Finalized) // TODO: also partial okay?
+	c.Unify(v, Finalized) // TODO: also partial okay?
 	// TODO: if the disjunction result originated from a literal value, we may
 	// consider the result closed to create more permanent errors.
 	return v
@@ -1388,7 +1388,7 @@
 			continue
 		}
 
-		c.Unify(c, a, Partial)
+		c.Unify(a, Partial)
 
 		n := &Vertex{status: Finalized}
 
diff --git a/internal/core/compile/builtin.go b/internal/core/compile/builtin.go
index ca93e99..e65f806 100644
--- a/internal/core/compile/builtin.go
+++ b/internal/core/compile/builtin.go
@@ -140,7 +140,7 @@
 		v.AddConjunct(adt.MakeRootConjunct(nil,
 			&adt.DisjunctionExpr{Values: d, HasDefaults: false},
 		))
-		c.Unify(c, v, adt.Finalized)
+		c.Unify(v, adt.Finalized)
 		return v
 	},
 }
diff --git a/internal/core/eval/eval.go b/internal/core/eval/eval.go
index 238db33..07bc3ac 100644
--- a/internal/core/eval/eval.go
+++ b/internal/core/eval/eval.go
@@ -27,20 +27,20 @@
 		Runtime: r,
 		Format:  format,
 	})
-	c.Unify(c, v, adt.Finalized)
+	c.Unify(v, adt.Finalized)
 }
 
 func New(r adt.Runtime) *Unifier {
-	return &Unifier{r: r, e: adt.NewUnifier(r)}
+	return &Unifier{r: r, e: NewContext(r, nil)}
 }
 
 type Unifier struct {
 	r adt.Runtime
-	e *adt.Unifier
+	e *adt.OpContext
 }
 
 func (e *Unifier) Unify(ctx *adt.OpContext, v *adt.Vertex, state adt.VertexStatus) {
-	e.e.Unify(ctx, v, state)
+	e.e.Unify(v, state)
 }
 
 func (e *Unifier) Stats() *adt.Stats {
@@ -50,18 +50,17 @@
 // TODO: Note: NewContext takes essentially a cue.Value. By making this
 // type more central, we can perhaps avoid context creation.
 func NewContext(r adt.Runtime, v *adt.Vertex) *adt.OpContext {
-	e := New(r)
-	return e.NewContext(v)
+	format := func(n adt.Node) string {
+		return debug.NodeString(r, n, printConfig)
+	}
+	return adt.New(v, &adt.Config{
+		Runtime: r,
+		Format:  format,
+	})
 }
 
 func (e *Unifier) NewContext(v *adt.Vertex) *adt.OpContext {
-	format := func(n adt.Node) string {
-		return debug.NodeString(e.r, n, printConfig)
-	}
-	return adt.New(v, &adt.Config{
-		Runtime: e.r,
-		Format:  format,
-	})
+	return NewContext(e.r, v)
 }
 
 var printConfig = &debug.Config{Compact: true}
diff --git a/internal/core/subsume/subsume.go b/internal/core/subsume/subsume.go
index ba00aab..734dfdb 100644
--- a/internal/core/subsume/subsume.go
+++ b/internal/core/subsume/subsume.go
@@ -107,7 +107,8 @@
 	v := &adt.Vertex{}
 	v.AddConjunct(adt.MakeRootConjunct(c.Env(0), a))
 	v.AddConjunct(adt.MakeRootConjunct(c.Env(0), b))
-	return c.Unifier.Evaluate(c, v)
+	x, _ := c.Evaluate(c.Env(0), v)
+	return x
 }
 
 func (s *subsumer) getError() (err errors.Error) {
diff --git a/internal/core/validate/validate_test.go b/internal/core/validate/validate_test.go
index e5ed4ff..9d395a2 100644
--- a/internal/core/validate/validate_test.go
+++ b/internal/core/validate/validate_test.go
@@ -196,7 +196,7 @@
 			if err != nil {
 				t.Fatal(err)
 			}
-			ctx.Unify(ctx, v, adt.Finalized)
+			ctx.Unify(v, adt.Finalized)
 			if tc.lookup != "" {
 				v = v.Lookup(adt.MakeIdentLabel(r, tc.lookup, "main"))
 			}