From 3d863fc0ecc3ea5d72ce09260ebfb1554a54eb62 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Thu, 3 Sep 2020 19:58:22 +0200 Subject: [PATCH] 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 Reviewed-by: CUE cueckoo --- cue/go.go | 2 +- cue/instance.go | 8 +- cue/types.go | 24 ++--- internal/core/adt/composite.go | 26 +++-- internal/core/adt/context.go | 7 +- internal/core/adt/default.go | 2 +- internal/core/adt/expr.go | 14 +-- internal/core/compile/builtin.go | 2 +- internal/core/compile/compile.go | 4 +- internal/core/convert/go.go | 10 +- internal/core/eval/closed.go | 25 ++--- internal/core/eval/closed_test.go | 21 ++-- internal/core/eval/disjunct.go | 10 +- internal/core/eval/eval.go | 155 ++++++++++++++-------------- internal/core/eval/optionals.go | 14 +-- internal/core/export/export.go | 2 +- internal/core/export/expr.go | 10 +- internal/core/subsume/structural.go | 6 +- pkg/internal/builtin.go | 2 +- 19 files changed, 171 insertions(+), 173 deletions(-) diff --git a/cue/go.go b/cue/go.go index 28399d93d..1d6717c8c 100644 --- a/cue/go.go +++ b/cue/go.go @@ -38,7 +38,7 @@ func init() { expr = &adt.Bottom{Err: err} } n := &adt.Vertex{} - n.AddConjunct(adt.MakeConjunct(nil, expr)) + n.AddConjunct(adt.MakeRootConjunct(nil, expr)) return Value{r.idx, n} // return convertType(runtime.(*Runtime), x) diff --git a/cue/instance.go b/cue/instance.go index 5b954eab3..7eb1958d4 100644 --- a/cue/instance.go +++ b/cue/instance.go @@ -75,7 +75,7 @@ func init() { st, ok := x.(*adt.Vertex) if !ok { st = &adt.Vertex{} - st.AddConjunct(adt.MakeConjunct(nil, x)) + st.AddConjunct(adt.MakeRootConjunct(nil, x)) } return v.ctx().index.addInst(&Instance{ root: st, @@ -231,7 +231,7 @@ func Merge(inst ...*Instance) *Instance { for _, i := range inst { w := i.Value() - v.AddConjunct(adt.MakeConjunct(nil, w.v.ToDataAll())) + v.AddConjunct(adt.MakeRootConjunct(nil, w.v.ToDataAll())) } v.Finalize(ctx) @@ -255,7 +255,7 @@ func (inst *Instance) Build(p *build.Instance) *Instance { v, err := compile.Files(&compile.Config{Scope: inst.root}, r, p.Files...) - v.AddConjunct(adt.MakeConjunct(nil, inst.root)) + v.AddConjunct(adt.MakeRootConjunct(nil, inst.root)) i := newInstance(idx, p, v) if rErr != nil { @@ -345,7 +345,7 @@ func (inst *Instance) Fill(x interface{}, path ...string) (*Instance, error) { } else { ctx := eval.NewContext(inst.index.Runtime, nil) expr := convert.GoValueToExpr(ctx, true, x) - u.AddConjunct(adt.MakeConjunct(nil, expr)) + u.AddConjunct(adt.MakeRootConjunct(nil, expr)) u.Finalize(ctx) } inst = inst.index.addInst(&Instance{ diff --git a/cue/types.go b/cue/types.go index 2981a84d0..0848bbbd6 100644 --- a/cue/types.go +++ b/cue/types.go @@ -570,7 +570,7 @@ func newErrValue(v Value, b *bottom) Value { node.Parent = v.v.Parent } node.UpdateStatus(adt.Finalized) - node.AddConjunct(adt.MakeConjunct(nil, b)) + node.AddConjunct(adt.MakeRootConjunct(nil, b)) return makeValue(v.idx, node) } @@ -590,7 +590,7 @@ func newValueRoot(ctx *context, x value) Value { return newVertexRoot(ctx, n) } node := &adt.Vertex{} - node.AddConjunct(adt.MakeConjunct(nil, x)) + node.AddConjunct(adt.MakeRootConjunct(nil, x)) return newVertexRoot(ctx, node) } @@ -648,7 +648,7 @@ func remakeValue(base Value, env *adt.Environment, v value) Value { return Value{base.idx, v} } n := &adt.Vertex{Parent: base.v.Parent, Label: base.v.Label} - n.AddConjunct(adt.MakeConjunct(env, v)) + n.AddConjunct(adt.MakeRootConjunct(env, v)) n = base.ctx().manifest(n) return makeValue(base.idx, n) } @@ -1556,7 +1556,7 @@ func (v Value) Fill(x interface{}, path ...string) Value { n, _ := value.(*adt.Vertex) if n == nil { n = &adt.Vertex{Label: v.v.Label, Parent: v.v.Parent} - n.AddConjunct(adt.MakeConjunct(nil, value)) + n.AddConjunct(adt.MakeRootConjunct(nil, value)) } else { n.Label = v.v.Label } @@ -1653,8 +1653,8 @@ func (v Value) Unify(w Value) Value { return v } n := &adt.Vertex{Parent: v.v.Parent, Label: v.v.Label} - n.AddConjunct(adt.MakeConjunct(nil, v.v)) - n.AddConjunct(adt.MakeConjunct(nil, w.v)) + n.AddConjunct(adt.MakeRootConjunct(nil, v.v)) + n.AddConjunct(adt.MakeRootConjunct(nil, w.v)) ctx := v.idx.newContext() n.Finalize(ctx.opCtx) @@ -1675,8 +1675,8 @@ func (v Value) UnifyAccept(w Value, accept Value) Value { } n := &adt.Vertex{Parent: v.v.Parent, Label: v.v.Label} - n.AddConjunct(adt.MakeConjunct(nil, v.v)) - n.AddConjunct(adt.MakeConjunct(nil, w.v)) + n.AddConjunct(adt.MakeRootConjunct(nil, v.v)) + n.AddConjunct(adt.MakeRootConjunct(nil, w.v)) e := eval.New(v.idx.Runtime) ctx := e.NewContext(n) @@ -2166,8 +2166,8 @@ func (v Value) Expr() (Op, []Value) { Closed: v.v.Closed, } b := a - a.AddConjunct(adt.MakeConjunct(env, n.Val)) - b.AddConjunct(adt.MakeConjunct(env, disjunct.Val)) + a.AddConjunct(adt.MakeRootConjunct(env, n.Val)) + b.AddConjunct(adt.MakeRootConjunct(env, disjunct.Val)) e := eval.New(v.idx.Runtime) ctx := e.NewContext(nil) @@ -2246,7 +2246,7 @@ func (v Value) Expr() (Op, []Value) { n := &adt.Vertex{ Parent: v.v.Parent, Label: v.v.Label} - c := adt.MakeConjunct(envEmbed, x) + c := adt.MakeRootConjunct(envEmbed, x) n.AddConjunct(c) n.Finalize(ctx) a = append(a, makeValue(v.idx, n)) @@ -2265,7 +2265,7 @@ func (v Value) Expr() (Op, []Value) { Parent: v.v.Parent, Label: v.v.Label, } - c := adt.MakeConjunct(env, &adt.StructLit{ + c := adt.MakeRootConjunct(env, &adt.StructLit{ Decls: fields, }) n.AddConjunct(c) diff --git a/internal/core/adt/composite.go b/internal/core/adt/composite.go index 999d4d818..3cbbbd1e5 100644 --- a/internal/core/adt/composite.go +++ b/internal/core/adt/composite.go @@ -91,10 +91,6 @@ type Environment struct { // TODO(perf): make the following public fields a shareable struct as it // mostly is going to be the same for child nodes. - // CloseID is a unique number that tracks a group of conjuncts that need - // belong to a single originating definition. - CloseID uint32 - // Cyclic indicates a structural cycle was detected for this conjunct or one // of its ancestors. Cyclic bool @@ -129,6 +125,8 @@ type Environment struct { cache map[Expr]Value } +type ID int32 + // evalCached is used to look up let expressions. Caching let expressions // prevents a possible combinatorial explosion. func (e *Environment) evalCached(c *OpContext, x Expr) Value { @@ -337,7 +335,7 @@ func ToVertex(v Value) *Vertex { status: Finalized, Value: x, } - n.AddConjunct(MakeConjunct(nil, v)) + n.AddConjunct(MakeRootConjunct(nil, v)) return n } } @@ -557,13 +555,25 @@ func (v *Vertex) appendListArcs(arcs []*Vertex) (err *Bottom) { type Conjunct struct { Env *Environment x Node + + // CloseID is a unique number that tracks a group of conjuncts that need + // belong to a single originating definition. + CloseID ID +} + +func (c *Conjunct) ID() ID { + return c.CloseID } // TODO(perf): replace with composite literal if this helps performance. -// MakeConjunct creates a conjunct from the given environment and node. +// MakeRootConjunct creates a conjunct from the given environment and node. // It panics if x cannot be used as an expression. -func MakeConjunct(env *Environment, x Node) Conjunct { +func MakeRootConjunct(env *Environment, x Node) Conjunct { + return MakeConjunct(env, x, 0) +} + +func MakeConjunct(env *Environment, x Node, id ID) Conjunct { if env == nil { // TODO: better is to pass one. env = &Environment{} @@ -573,7 +583,7 @@ func MakeConjunct(env *Environment, x Node) Conjunct { default: panic(fmt.Sprintf("invalid Node type %T", x)) } - return Conjunct{env, x} + return Conjunct{env, x, id} } func (c *Conjunct) Source() ast.Node { diff --git a/internal/core/adt/context.go b/internal/core/adt/context.go index 9a36cc11d..7cb2aa090 100644 --- a/internal/core/adt/context.go +++ b/internal/core/adt/context.go @@ -160,9 +160,6 @@ func (c *OpContext) spawn(node *Vertex) *OpContext { sub := *c node.Parent = c.e.Vertex sub.e = &Environment{Up: c.e, Vertex: node} - if c.e != nil { - sub.e.CloseID = c.e.CloseID - } return &sub } @@ -290,9 +287,7 @@ func (c *OpContext) PushState(env *Environment, src ast.Node) (saved frame) { if src != nil { c.src = src } - if env != nil { - c.e = env - } + c.e = env return saved } diff --git a/internal/core/adt/default.go b/internal/core/adt/default.go index 2dd1ff7b4..fc922bd1a 100644 --- a/internal/core/adt/default.go +++ b/internal/core/adt/default.go @@ -69,7 +69,7 @@ func (v *Vertex) Default() *Vertex { for _, c := range v.Conjuncts { // TODO: preserve field information. expr, _ := stripNonDefaults(c.Expr()) - w.Conjuncts = append(w.Conjuncts, MakeConjunct(c.Env, expr)) + w.Conjuncts = append(w.Conjuncts, MakeRootConjunct(c.Env, expr)) } return w diff --git a/internal/core/adt/expr.go b/internal/core/adt/expr.go index 8fbdcec8d..4b53894b4 100644 --- a/internal/core/adt/expr.go +++ b/internal/core/adt/expr.go @@ -40,7 +40,7 @@ func (x *StructLit) Source() ast.Node { return x.Src } func (x *StructLit) evaluate(c *OpContext) Value { e := c.Env(0) - v := &Vertex{Conjuncts: []Conjunct{{e, x}}} + v := &Vertex{Conjuncts: []Conjunct{{e, x, 0}}} c.Unifier.Unify(c, v, Finalized) // TODO: also partial okay? return v } @@ -168,7 +168,7 @@ func (x *ListLit) Source() ast.Node { func (x *ListLit) evaluate(c *OpContext) Value { e := c.Env(0) - v := &Vertex{Conjuncts: []Conjunct{{e, x}}} + v := &Vertex{Conjuncts: []Conjunct{{e, x, 0}}} c.Unifier.Unify(c, v, Finalized) // TODO: also partial okay? return v } @@ -547,7 +547,7 @@ func (x *LetReference) resolve(c *OpContext) *Vertex { e := c.Env(x.UpCount) label := e.Vertex.Label // Anonymous arc. - return &Vertex{Parent: nil, Label: label, Conjuncts: []Conjunct{{e, x.X}}} + return &Vertex{Parent: nil, Label: label, Conjuncts: []Conjunct{{e, x.X, 0}}} } func (x *LetReference) evaluate(c *OpContext) Value { @@ -822,7 +822,7 @@ func (x *BinaryExpr) evaluate(c *OpContext) Value { env := c.Env(0) if x.Op == AndOp { // Anonymous Arc - v := Vertex{Conjuncts: []Conjunct{{env, x}}} + v := Vertex{Conjuncts: []Conjunct{{env, x, 0}}} return c.Unifier.Evaluate(c, &v) } @@ -1094,7 +1094,7 @@ func (x *DisjunctionExpr) Source() ast.Node { func (x *DisjunctionExpr) evaluate(c *OpContext) Value { e := c.Env(0) - v := &Vertex{Conjuncts: []Conjunct{{e, x}}} + v := &Vertex{Conjuncts: []Conjunct{{e, x, 0}}} c.Unifier.Unify(c, 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. @@ -1178,7 +1178,7 @@ func (x *ForClause) yield(c *OpContext, f YieldFunc) { if x.Key != 0 { v := &Vertex{Label: x.Key} key := a.Label.ToValue(c) - v.AddConjunct(MakeConjunct(c.Env(0), key)) + v.AddConjunct(MakeRootConjunct(c.Env(0), key)) v.SetValue(c, Finalized, key) n.Arcs = append(n.Arcs, v) } @@ -1234,7 +1234,7 @@ func (x *LetClause) Source() ast.Node { func (x *LetClause) yield(c *OpContext, f YieldFunc) { n := &Vertex{Arcs: []*Vertex{ - {Label: x.Label, Conjuncts: []Conjunct{{c.Env(0), x.Expr}}}, + {Label: x.Label, Conjuncts: []Conjunct{{c.Env(0), x.Expr, 0}}}, }} x.Dst.yield(c.spawn(n), f) } diff --git a/internal/core/compile/builtin.go b/internal/core/compile/builtin.go index 8934019da..75972dcac 100644 --- a/internal/core/compile/builtin.go +++ b/internal/core/compile/builtin.go @@ -128,7 +128,7 @@ var orBuiltin = &adt.Builtin{ } v := &adt.Vertex{} // TODO: make a Disjunction. - v.AddConjunct(adt.MakeConjunct(nil, + v.AddConjunct(adt.MakeRootConjunct(nil, &adt.DisjunctionExpr{Values: d, HasDefaults: false}, )) c.Unify(c, v, adt.Finalized) diff --git a/internal/core/compile/compile.go b/internal/core/compile/compile.go index dbb556a1a..eab01fd54 100644 --- a/internal/core/compile/compile.go +++ b/internal/core/compile/compile.go @@ -241,7 +241,7 @@ func (c *compiler) compileFiles(a []*ast.File) *adt.Vertex { // Or value? c.pushScope(nil, 0, file) // File scope v := &adt.StructLit{Src: file} c.addDecls(v, file.Decls) - res.Conjuncts = append(res.Conjuncts, adt.MakeConjunct(nil, v)) + res.Conjuncts = append(res.Conjuncts, adt.MakeRootConjunct(nil, v)) c.popScope() } @@ -278,7 +278,7 @@ func (c *compiler) compileExpr(x ast.Expr) adt.Conjunct { // env = e } - return adt.MakeConjunct(env, expr) + return adt.MakeRootConjunct(env, expr) } // resolve assumes that all existing resolutions are legal. Validation should diff --git a/internal/core/convert/go.go b/internal/core/convert/go.go index 067321d43..2a4173b23 100644 --- a/internal/core/convert/go.go +++ b/internal/core/convert/go.go @@ -63,7 +63,7 @@ func toValue(e adt.Expr) adt.Value { return v } obj := &adt.Vertex{} - obj.AddConjunct(adt.MakeConjunct(nil, e)) + obj.AddConjunct(adt.MakeRootConjunct(nil, e)) return obj } @@ -400,7 +400,7 @@ func convertRec(ctx *adt.OpContext, nilIsTop bool, x interface{}) adt.Value { case reflect.Struct: obj := &adt.StructLit{Src: src} v := &adt.Vertex{} - v.AddConjunct(adt.MakeConjunct(nil, obj)) + v.AddConjunct(adt.MakeRootConjunct(nil, obj)) v.SetValue(ctx, adt.Finalized, &adt.StructMarker{}) t := value.Type() @@ -441,7 +441,7 @@ func convertRec(ctx *adt.OpContext, nilIsTop bool, x interface{}) adt.Value { arc.Label = f } else { arc = &adt.Vertex{Label: f, Value: sub} - arc.AddConjunct(adt.MakeConjunct(nil, sub)) + arc.AddConjunct(adt.MakeRootConjunct(nil, sub)) } v.Arcs = append(v.Arcs, arc) } @@ -451,7 +451,7 @@ func convertRec(ctx *adt.OpContext, nilIsTop bool, x interface{}) adt.Value { case reflect.Map: obj := &adt.StructLit{Src: src} v := &adt.Vertex{Value: &adt.StructMarker{}} - v.AddConjunct(adt.MakeConjunct(nil, obj)) + v.AddConjunct(adt.MakeRootConjunct(nil, obj)) v.SetValue(ctx, adt.Finalized, &adt.StructMarker{}) t := value.Type() @@ -492,7 +492,7 @@ func convertRec(ctx *adt.OpContext, nilIsTop bool, x interface{}) adt.Value { arc.Label = f } else { arc = &adt.Vertex{Label: f, Value: sub} - arc.AddConjunct(adt.MakeConjunct(nil, sub)) + arc.AddConjunct(adt.MakeRootConjunct(nil, sub)) } v.Arcs = append(v.Arcs, arc) } diff --git a/internal/core/eval/closed.go b/internal/core/eval/closed.go index 56a0d7fa4..175b08de1 100644 --- a/internal/core/eval/closed.go +++ b/internal/core/eval/closed.go @@ -143,7 +143,7 @@ func newDisjunctionAcceptor(x *adt.Disjunction) adt.Acceptor { // any value. type CloseDef struct { Src adt.Node // for error reporting - ID uint32 + ID adt.ID IsAnd bool List []*CloseDef } @@ -161,7 +161,7 @@ func isOr(c *CloseDef) bool { // a CloseDef tree based on replacement information gathered during evaluation // of this flat list. // -func updateClosed(c *CloseDef, replace map[uint32]*CloseDef) *CloseDef { // used in eval.go +func updateClosed(c *CloseDef, replace map[adt.ID]*CloseDef) *CloseDef { // used in eval.go // Insert an entry for CloseID 0 if we are about to replace it. By default // 0, which is the majority case, is omitted. if c != nil && replace[0] != nil && !containsClosed(c, 0) { @@ -190,7 +190,7 @@ func updateClosed(c *CloseDef, replace map[uint32]*CloseDef) *CloseDef { // used return c } -func updateClosedRec(c *CloseDef, replace map[uint32]*CloseDef) *CloseDef { +func updateClosedRec(c *CloseDef, replace map[adt.ID]*CloseDef) *CloseDef { if c == nil { return nil } @@ -239,18 +239,13 @@ func updateClosedRec(c *CloseDef, replace map[uint32]*CloseDef) *CloseDef { // UpdateReplace is called after evaluating a conjunct at the top of the arc // to update the replacement information with the gathered CloseDef info. -func (n *nodeContext) updateReplace(env *adt.Environment) { // used in eval.go +func (n *nodeContext) updateReplace(id adt.ID) { // used in eval.go if n.newClose == nil { return } if n.replace == nil { - n.replace = make(map[uint32]*CloseDef) - } - - id := uint32(0) - if env != nil { - id = env.CloseID + n.replace = make(map[adt.ID]*CloseDef) } n.replace[id] = updateClose(n.replace[id], n.newClose) @@ -310,7 +305,7 @@ func (n *nodeContext) addAnd(c *CloseDef) { // used in eval.go } } -func (n *nodeContext) addOr(parentID uint32, c *CloseDef) { // used in eval.go +func (n *nodeContext) addOr(parentID adt.ID, c *CloseDef) { // used in eval.go switch { case n.newClose == nil: d := &CloseDef{ID: parentID, List: []*CloseDef{{ID: parentID}}} @@ -337,6 +332,7 @@ func (n *acceptor) verifyArcAllowed(ctx *adt.OpContext, f adt.Feature) *adt.Bott // more clever and only generate this when it is a user error. filter := f.IsString() || f == adt.InvalidLabel if filter && !n.verifyArcRecursive(ctx, n.tree, f) { + collectPositions(ctx, n.tree) label := f.SelectorString(ctx) return ctx.NewErrf("field `%s` not allowed", label) } @@ -365,9 +361,9 @@ func (n *acceptor) verifyArcRecursive(ctx *adt.OpContext, c *CloseDef, f adt.Fea // verifyDefinition reports whether f is a valid member for any of the fieldSets // with the same closeID. -func (n *acceptor) verifyDefinition(ctx *adt.OpContext, closeID uint32, f adt.Feature) (ok bool) { +func (n *acceptor) verifyDefinition(ctx *adt.OpContext, closeID adt.ID, f adt.Feature) (ok bool) { for _, o := range n.fields { - if o.env.CloseID != closeID { + if o.id != closeID { continue } @@ -387,7 +383,6 @@ func (n *acceptor) verifyDefinition(ctx *adt.OpContext, closeID uint32, f adt.Fe } } } - collectPositions(ctx, n.tree) for _, o := range n.fields { if o.pos != nil { ctx.AddPosition(o.pos) @@ -407,7 +402,7 @@ func collectPositions(ctx *adt.OpContext, c *CloseDef) { // containsClosed reports whether c contains any CloseDef with ID x, // recursively. -func containsClosed(c *CloseDef, x uint32) bool { +func containsClosed(c *CloseDef, x adt.ID) bool { if c.ID == x && !c.IsAnd { return true } diff --git a/internal/core/eval/closed_test.go b/internal/core/eval/closed_test.go index c0ed27888..45511f6c7 100644 --- a/internal/core/eval/closed_test.go +++ b/internal/core/eval/closed_test.go @@ -17,6 +17,7 @@ package eval import ( "testing" + "cuelang.org/go/internal/core/adt" "github.com/google/go-cmp/cmp" ) @@ -24,12 +25,12 @@ func TestRewriteClosed(t *testing.T) { testCases := []struct { desc string close *CloseDef - replace map[uint32]*CloseDef + replace map[adt.ID]*CloseDef want *CloseDef }{{ desc: "introduce new", close: nil, - replace: map[uint32]*CloseDef{ + replace: map[adt.ID]*CloseDef{ 0: {ID: 2, IsAnd: false, List: nil}, }, want: &CloseDef{ @@ -40,7 +41,7 @@ func TestRewriteClosed(t *testing.T) { close: &CloseDef{ ID: 1, }, - replace: map[uint32]*CloseDef{ + replace: map[adt.ID]*CloseDef{ 0: {ID: 2, IsAnd: false, List: nil}, 1: nil, // keep 1 }, @@ -53,7 +54,7 @@ func TestRewriteClosed(t *testing.T) { close: &CloseDef{ ID: 1, }, - replace: map[uint32]*CloseDef{ + replace: map[adt.ID]*CloseDef{ 1: {ID: 1, IsAnd: true, List: []*CloseDef{{ID: 2}, {ID: 3}}}, }, want: &CloseDef{ @@ -66,7 +67,7 @@ func TestRewriteClosed(t *testing.T) { close: &CloseDef{ ID: 1, }, - replace: map[uint32]*CloseDef{ + replace: map[adt.ID]*CloseDef{ 0: nil, }, want: nil, @@ -80,7 +81,7 @@ func TestRewriteClosed(t *testing.T) { {ID: 3}, }, }, - replace: map[uint32]*CloseDef{2: nil}, + replace: map[adt.ID]*CloseDef{2: nil}, want: &CloseDef{ID: 2}, }, { desc: "eliminateAllEmbeddings", @@ -91,7 +92,7 @@ func TestRewriteClosed(t *testing.T) { {ID: 3}, }, }, - replace: map[uint32]*CloseDef{0: {ID: 4}, 4: nil}, + replace: map[adt.ID]*CloseDef{0: {ID: 4}, 4: nil}, want: &CloseDef{ID: 4}, }, { // Do not eliminate an embedding that has a replacement. @@ -103,7 +104,7 @@ func TestRewriteClosed(t *testing.T) { {ID: 3}, }, }, - replace: map[uint32]*CloseDef{ + replace: map[adt.ID]*CloseDef{ 2: nil, 3: {ID: 3, IsAnd: true, List: []*CloseDef{{ID: 4}, {ID: 5}}}, }, @@ -134,7 +135,7 @@ func TestRewriteClosed(t *testing.T) { {ID: 0}, }, }, - replace: map[uint32]*CloseDef{0: {ID: 3}}, + replace: map[adt.ID]*CloseDef{0: {ID: 3}}, want: &CloseDef{ID: 3}, }, { // Select b within a @@ -156,7 +157,7 @@ func TestRewriteClosed(t *testing.T) { {ID: 0}, }, }, - replace: map[uint32]*CloseDef{ + replace: map[adt.ID]*CloseDef{ 0: {IsAnd: true, List: []*CloseDef{{ID: 3}, {ID: 4}}}, }, want: &CloseDef{ diff --git a/internal/core/eval/disjunct.go b/internal/core/eval/disjunct.go index 27c479d81..6028093bb 100644 --- a/internal/core/eval/disjunct.go +++ b/internal/core/eval/disjunct.go @@ -87,7 +87,7 @@ type envDisjunct struct { env *adt.Environment values []disjunct numDefaults int - cloneID uint32 + cloneID adt.ID isEmbed bool } @@ -96,7 +96,7 @@ type disjunct struct { isDefault bool } -func (n *nodeContext) addDisjunction(env *adt.Environment, x *adt.DisjunctionExpr, cloneID uint32, isEmbed bool) { +func (n *nodeContext) addDisjunction(env *adt.Environment, x *adt.DisjunctionExpr, cloneID adt.ID, isEmbed bool) { a := []disjunct{} numDefaults := 0 @@ -116,7 +116,7 @@ func (n *nodeContext) addDisjunction(env *adt.Environment, x *adt.DisjunctionExp envDisjunct{env, a, numDefaults, cloneID, isEmbed}) } -func (n *nodeContext) addDisjunctionValue(env *adt.Environment, x *adt.Disjunction, cloneID uint32, isEmbed bool) { +func (n *nodeContext) addDisjunctionValue(env *adt.Environment, x *adt.Disjunction, cloneID adt.ID, isEmbed bool) { a := []disjunct{} for i, v := range x.Values { @@ -297,8 +297,8 @@ func (n *nodeContext) insertSingleDisjunct(p int, d envDisjunct, isSub bool) (mo k := n.stack[p] v := d.values[k] n.isFinal = n.isFinal && k == len(d.values)-1 - c := adt.MakeConjunct(d.env, v.expr) - n.addExprConjunct(c, d.cloneID, d.isEmbed) + c := adt.MakeConjunct(d.env, v.expr, d.cloneID) + n.addExprConjunct(c, d.isEmbed) for n.expandOne() { } diff --git a/internal/core/eval/eval.go b/internal/core/eval/eval.go index 647d4b8c6..bc5a477bf 100644 --- a/internal/core/eval/eval.go +++ b/internal/core/eval/eval.go @@ -112,12 +112,12 @@ var incompleteSentinel = &adt.Bottom{ 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 @@ func (e *Evaluator) evalVertex(c *adt.OpContext, v *adt.Vertex, state adt.Vertex 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 @@ func (n *nodeContext) updateClosedInfo() { 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 @@ type nodeContext struct { 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 @@ func (n *nodeContext) maybeSetCache() { 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 @@ type envList struct { 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 @@ func (n *nodeContext) addErr(err errors.Error) { // 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 @@ outer: } } 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 @@ outer: 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 @@ outer: // 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 @@ outer: 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 @@ func updateCyclic(c adt.Conjunct, cyclic bool, deref *adt.Vertex) adt.Conjunct { 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 @@ func (n *nodeContext) insertClosed(arc *adt.Vertex, id uint32, cyclic bool, dere 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 @@ func (n *nodeContext) addValueConjunct(env *adt.Environment, v adt.Value) { 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 @@ func (n *nodeContext) addValueConjunct(env *adt.Environment, v adt.Value) { 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 @@ func (n *nodeContext) addValueConjunct(env *adt.Environment, v adt.Value) { 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 @@ func (n *nodeContext) addValueConjunct(env *adt.Environment, v adt.Value) { 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 @@ func (n *nodeContext) addValueConjunct(env *adt.Environment, v adt.Value) { 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 @@ func (n *nodeContext) addValueConjunct(env *adt.Environment, v adt.Value) { 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) addValueConjunct(env *adt.Environment, v adt.Value) { 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 @@ func (n *nodeContext) addStruct( 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 @@ func (n *nodeContext) addStruct( // } // } 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 @@ func (n *nodeContext) addStruct( 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 @@ func (n *nodeContext) addStruct( 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 @@ func (n *nodeContext) addStruct( 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 @@ func (n *nodeContext) addStruct( 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 @@ func (n *nodeContext) expandOne() (done bool) { 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 @@ func (n *nodeContext) injectDynamic() (progress bool) { 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 @@ func (n *nodeContext) injectEmbedded(all *[]envYield) (progress bool) { } 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 @@ func (n *nodeContext) addLists(c *adt.OpContext) (oneOfTheLists adt.Expr) { 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 @@ outer: 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 @@ outer: 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 @@ outer: 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) diff --git a/internal/core/eval/optionals.go b/internal/core/eval/optionals.go index 0426c1853..947dd19dd 100644 --- a/internal/core/eval/optionals.go +++ b/internal/core/eval/optionals.go @@ -23,11 +23,13 @@ import ( // fieldSet represents the fields for a single struct literal, along // the constraints of fields that may be added. type fieldSet struct { - pos adt.Node + next *fieldSet + pos adt.Node // TODO: look at consecutive identical environments to figure out // what belongs to same definition? env *adt.Environment + id adt.ID // field marks the optional conjuncts of all explicit fields. // Required fields are marked as empty @@ -104,7 +106,7 @@ func (o *fieldSet) MatchAndInsert(c *adt.OpContext, arc *adt.Vertex) { } if p < len(o.fields) { for _, e := range o.fields[p].optional { - arc.AddConjunct(adt.MakeConjunct(env, e)) + arc.AddConjunct(adt.MakeConjunct(env, e, o.id)) } return } @@ -122,7 +124,7 @@ func (o *fieldSet) MatchAndInsert(c *adt.OpContext, arc *adt.Vertex) { if f.check.Match(c, arc.Label) { matched = true if f.expr != nil { - arc.AddConjunct(adt.MakeConjunct(&bulkEnv, f.expr)) + arc.AddConjunct(adt.MakeConjunct(&bulkEnv, f.expr, o.id)) } } } @@ -132,7 +134,7 @@ func (o *fieldSet) MatchAndInsert(c *adt.OpContext, arc *adt.Vertex) { // match others for _, x := range o.additional { - arc.AddConjunct(adt.MakeConjunct(env, x)) + arc.AddConjunct(adt.MakeConjunct(env, x, o.id)) } } @@ -242,13 +244,13 @@ func (m patternMatcher) Match(c *adt.OpContext, f adt.Feature) bool { v := adt.Vertex{} v.AddConjunct(adt.Conjunct(m)) label := f.ToValue(c) - v.AddConjunct(adt.MakeConjunct(m.Env, label)) + v.AddConjunct(adt.MakeRootConjunct(m.Env, label)) v.Finalize(c) b, _ := v.Value.(*adt.Bottom) return b == nil } func (o *fieldSet) newPatternMatcher(ctx *adt.OpContext, x adt.Value) fieldMatcher { - c := adt.MakeConjunct(o.env, x) + c := adt.MakeRootConjunct(o.env, x) return patternMatcher(c) } diff --git a/internal/core/export/export.go b/internal/core/export/export.go index 51f220970..733c2023d 100644 --- a/internal/core/export/export.go +++ b/internal/core/export/export.go @@ -291,7 +291,7 @@ func (e *exporter) frame(upCount int32) *frame { func (e *exporter) setDocs(x adt.Node) { f := e.stack[len(e.stack)-1] - f.docSources = []adt.Conjunct{adt.MakeConjunct(nil, x)} + f.docSources = []adt.Conjunct{adt.MakeRootConjunct(nil, x)} e.stack[len(e.stack)-1] = f } diff --git a/internal/core/export/expr.go b/internal/core/export/expr.go index 3edc5f5b1..7f130f538 100644 --- a/internal/core/export/expr.go +++ b/internal/core/export/expr.go @@ -65,7 +65,7 @@ func (e *exporter) expr(v adt.Expr) (result ast.Expr) { return e.mergeValues(adt.InvalidLabel, x, a, x.Conjuncts...) case *adt.StructLit: - c := adt.MakeConjunct(nil, x) + c := adt.MakeRootConjunct(nil, x) return e.mergeValues(adt.InvalidLabel, nil, []conjunct{{c: c, up: 0}}, c) case adt.Value: @@ -204,7 +204,7 @@ type conjuncts struct { func (c *conjuncts) addConjunct(f adt.Feature, env *adt.Environment, n adt.Node) { x := c.fields[f] - v := adt.MakeConjunct(env, n) + v := adt.MakeRootConjunct(env, n) x.conjuncts = append(x.conjuncts, conjunct{ c: v, up: c.top().upCount, @@ -282,7 +282,7 @@ func (e *conjuncts) addExpr(env *adt.Environment, x adt.Expr) { switch x.(type) { case *adt.StructMarker, *adt.Top: default: - e.values.AddConjunct(adt.MakeConjunct(env, x)) // GOBBLE TOP + e.values.AddConjunct(adt.MakeRootConjunct(env, x)) // GOBBLE TOP } case *adt.BinaryExpr: @@ -291,14 +291,14 @@ func (e *conjuncts) addExpr(env *adt.Environment, x adt.Expr) { e.addExpr(env, x.X) e.addExpr(env, x.Y) case isSelfContained(x): - e.values.AddConjunct(adt.MakeConjunct(env, x)) + e.values.AddConjunct(adt.MakeRootConjunct(env, x)) default: e.exprs = append(e.exprs, e.expr(x)) } default: if isSelfContained(x) { - e.values.AddConjunct(adt.MakeConjunct(env, x)) + e.values.AddConjunct(adt.MakeRootConjunct(env, x)) } else { e.exprs = append(e.exprs, e.expr(x)) } diff --git a/internal/core/subsume/structural.go b/internal/core/subsume/structural.go index 16e7a0ee4..bc581cbcd 100644 --- a/internal/core/subsume/structural.go +++ b/internal/core/subsume/structural.go @@ -42,7 +42,7 @@ func (s *subsumer) conjunct(gt, lt adt.Conjunct) bool { } func (s *subsumer) c(env *adt.Environment, x adt.Expr) adt.Conjunct { - return adt.MakeConjunct(env, x) + return adt.MakeRootConjunct(env, x) } func isBottomConjunct(c adt.Conjunct) bool { @@ -247,12 +247,12 @@ func (c *collatedDecls) collate(env *adt.Environment, s *adt.StructLit) { case *adt.Field: e := c.fields[x.Label] e.required = true - e.conjuncts = append(e.conjuncts, adt.MakeConjunct(env, x)) + e.conjuncts = append(e.conjuncts, adt.MakeRootConjunct(env, x)) c.fields[x.Label] = e case *adt.OptionalField: e := c.fields[x.Label] - e.conjuncts = append(e.conjuncts, adt.MakeConjunct(env, x)) + e.conjuncts = append(e.conjuncts, adt.MakeRootConjunct(env, x)) c.fields[x.Label] = e c.hasOptional = true diff --git a/pkg/internal/builtin.go b/pkg/internal/builtin.go index 167bbece4..ac692229b 100644 --- a/pkg/internal/builtin.go +++ b/pkg/internal/builtin.go @@ -64,7 +64,7 @@ func (p *Package) MustCompile(ctx *adt.OpContext, pkgName string) *adt.Vertex { pkgLabel := ctx.StringLabel(pkgName) st := &adt.StructLit{} if len(p.Native) > 0 { - obj.AddConjunct(adt.MakeConjunct(nil, st)) + obj.AddConjunct(adt.MakeRootConjunct(nil, st)) } for _, b := range p.Native { b.Pkg = pkgLabel