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"))
}