github.com/solo-io/cue@v0.4.7/internal/core/adt/composite.go (about)

     1  // Copyright 2020 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package adt
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/solo-io/cue/cue/ast"
    21  	"github.com/solo-io/cue/cue/errors"
    22  	"github.com/solo-io/cue/cue/token"
    23  )
    24  
    25  // TODO: unanswered questions about structural cycles:
    26  //
    27  // 1. When detecting a structural cycle, should we consider this as:
    28  //    a) an unevaluated value,
    29  //    b) an incomplete error (which does not affect parent validity), or
    30  //    c) a special value.
    31  //
    32  // Making it an error is the simplest way to ensure reentrancy is disallowed:
    33  // without an error it would require an additional mechanism to stop reentrancy
    34  // from continuing to process. Even worse, in some cases it may only partially
    35  // evaluate, resulting in unexpected results. For this reason, we are taking
    36  // approach `b` for now.
    37  //
    38  // This has some consequences of how disjunctions are treated though. Consider
    39  //
    40  //     list: {
    41  //        head: _
    42  //        tail: list | null
    43  //     }
    44  //
    45  // When making it an error, evaluating the above will result in
    46  //
    47  //     list: {
    48  //        head: _
    49  //        tail: null
    50  //     }
    51  //
    52  // because list will result in a structural cycle, and thus an error, it will be
    53  // stripped from the disjunction. This may or may not be a desirable property. A
    54  // nice thing is that it is not required to write `list | *null`. A disadvantage
    55  // is that this is perhaps somewhat inexplicit.
    56  //
    57  // When not making it an error (and simply cease evaluating child arcs upon
    58  // cycle detection), the result would be:
    59  //
    60  //     list: {
    61  //        head: _
    62  //        tail: list | null
    63  //     }
    64  //
    65  // In other words, an evaluation would result in a cycle and thus an error.
    66  // Implementations can recognize such cases by having unevaluated arcs. An
    67  // explicit structure cycle marker would probably be less error prone.
    68  //
    69  // Note that in both cases, a reference to list will still use the original
    70  // conjuncts, so the result will be the same for either method in this case.
    71  //
    72  //
    73  // 2. Structural cycle allowance.
    74  //
    75  // Structural cycle detection disallows reentrancy as well. This means one
    76  // cannot use structs for recursive computation. This will probably preclude
    77  // evaluation of some configuration. Given that there is no real alternative
    78  // yet, we could allow structural cycle detection to be optionally disabled.
    79  
    80  // An Environment links the parent scopes for identifier lookup to a composite
    81  // node. Each conjunct that make up node in the tree can be associated with
    82  // a different environment (although some conjuncts may share an Environment).
    83  type Environment struct {
    84  	Up     *Environment
    85  	Vertex *Vertex
    86  
    87  	// DynamicLabel is only set when instantiating a field from a pattern
    88  	// constraint. It is used to resolve label references.
    89  	DynamicLabel Feature
    90  
    91  	// TODO(perf): make the following public fields a shareable struct as it
    92  	// mostly is going to be the same for child nodes.
    93  
    94  	// Cyclic indicates a structural cycle was detected for this conjunct or one
    95  	// of its ancestors.
    96  	Cyclic bool
    97  
    98  	// Deref keeps track of nodes that should dereference to Vertex. It is used
    99  	// for detecting structural cycle.
   100  	//
   101  	// The detection algorithm is based on Tomabechi's quasi-destructive graph
   102  	// unification. This detection requires dependencies to be resolved into
   103  	// fully dereferenced vertices. This is not the case in our algorithm:
   104  	// the result of evaluating conjuncts is placed into dereferenced vertices
   105  	// _after_ they are evaluated, but the Environment still points to the
   106  	// non-dereferenced context.
   107  	//
   108  	// In order to be able to detect structural cycles, we need to ensure that
   109  	// at least one node that is part of a cycle in the context in which
   110  	// conjunctions are evaluated dereferences correctly.
   111  	//
   112  	// The only field necessary to detect a structural cycle, however, is
   113  	// the Status field of the Vertex. So rather than dereferencing a node
   114  	// proper, it is sufficient to copy the Status of the dereferenced nodes
   115  	// to these nodes (will always be EvaluatingArcs).
   116  	Deref []*Vertex
   117  
   118  	// Cycles contains vertices for which cycles are detected. It is used
   119  	// for tracking self-references within structural cycles.
   120  	//
   121  	// Unlike Deref, Cycles is not incremented with child nodes.
   122  	// TODO: Cycles is always a tail end of Deref, so this can be optimized.
   123  	Cycles []*Vertex
   124  
   125  	cache map[Expr]Value
   126  }
   127  
   128  type ID int32
   129  
   130  // evalCached is used to look up let expressions. Caching let expressions
   131  // prevents a possible combinatorial explosion.
   132  func (e *Environment) evalCached(c *OpContext, x Expr) Value {
   133  	if v, ok := x.(Value); ok {
   134  		return v
   135  	}
   136  	v, ok := e.cache[x]
   137  	if !ok {
   138  		if e.cache == nil {
   139  			e.cache = map[Expr]Value{}
   140  		}
   141  		env, src := c.e, c.src
   142  		c.e, c.src = e, x.Source()
   143  		v = c.evalState(x, Partial) // TODO: should this be Finalized?
   144  		c.e, c.src = env, src
   145  		e.cache[x] = v
   146  	}
   147  	return v
   148  }
   149  
   150  // A Vertex is a node in the value tree. It may be a leaf or internal node.
   151  // It may have arcs to represent elements of a fully evaluated struct or list.
   152  //
   153  // For structs, it only contains definitions and concrete fields.
   154  // optional fields are dropped.
   155  //
   156  // It maintains source information such as a list of conjuncts that contributed
   157  // to the value.
   158  type Vertex struct {
   159  	// Parent links to a parent Vertex. This parent should only be used to
   160  	// access the parent's Label field to find the relative location within a
   161  	// tree.
   162  	Parent *Vertex
   163  
   164  	// Label is the feature leading to this vertex.
   165  	Label Feature
   166  
   167  	// State:
   168  	//   eval: nil, BaseValue: nil -- unevaluated
   169  	//   eval: *,   BaseValue: nil -- evaluating
   170  	//   eval: *,   BaseValue: *   -- finalized
   171  	//
   172  	state *nodeContext
   173  	// TODO: move the following status fields to nodeContext.
   174  
   175  	// status indicates the evaluation progress of this vertex.
   176  	status VertexStatus
   177  
   178  	// isData indicates that this Vertex is to be interepreted as data: pattern
   179  	// and additional constraints, as well as optional fields, should be
   180  	// ignored.
   181  	isData                bool
   182  	Closed                bool
   183  	nonMonotonicReject    bool
   184  	nonMonotonicInsertGen int32
   185  	nonMonotonicLookupGen int32
   186  
   187  	// EvalCount keeps track of temporary dereferencing during evaluation.
   188  	// If EvalCount > 0, status should be considered to be EvaluatingArcs.
   189  	EvalCount int32
   190  
   191  	// SelfCount is used for tracking self-references.
   192  	SelfCount int32
   193  
   194  	// BaseValue is the value associated with this vertex. For lists and structs
   195  	// this is a sentinel value indicating its kind.
   196  	BaseValue BaseValue
   197  
   198  	// ChildErrors is the collection of all errors of children.
   199  	ChildErrors *Bottom
   200  
   201  	// The parent of nodes can be followed to determine the path within the
   202  	// configuration of this node.
   203  	// Value  Value
   204  	Arcs []*Vertex // arcs are sorted in display order.
   205  
   206  	// Conjuncts lists the structs that ultimately formed this Composite value.
   207  	// This includes all selected disjuncts.
   208  	//
   209  	// This value may be nil, in which case the Arcs are considered to define
   210  	// the final value of this Vertex.
   211  	Conjuncts []Conjunct
   212  
   213  	// Structs is a slice of struct literals that contributed to this value.
   214  	// This information is used to compute the topological sort of arcs.
   215  	Structs []*StructInfo
   216  }
   217  
   218  type StructInfo struct {
   219  	*StructLit
   220  
   221  	Env *Environment
   222  
   223  	CloseInfo
   224  
   225  	// Embed indicates the struct in which this struct is embedded (originally),
   226  	// or nil if this is a root structure.
   227  	// Embed   *StructInfo
   228  	// Context *RefInfo // the location from which this struct originates.
   229  	Disable bool
   230  
   231  	Embedding bool
   232  }
   233  
   234  // TODO(perf): this could be much more aggressive for eliminating structs that
   235  // are immaterial for closing.
   236  func (s *StructInfo) useForAccept() bool {
   237  	if c := s.closeInfo; c != nil {
   238  		return !c.noCheck
   239  	}
   240  	return true
   241  }
   242  
   243  // VertexStatus indicates the evaluation progress of a Vertex.
   244  type VertexStatus int8
   245  
   246  const (
   247  	// Unprocessed indicates a Vertex has not been processed before.
   248  	// Value must be nil.
   249  	Unprocessed VertexStatus = iota
   250  
   251  	// Evaluating means that the current Vertex is being evaluated. If this is
   252  	// encountered it indicates a reference cycle. Value must be nil.
   253  	Evaluating
   254  
   255  	// Partial indicates that the result was only partially evaluated. It will
   256  	// need to be fully evaluated to get a complete results.
   257  	//
   258  	// TODO: this currently requires a renewed computation. Cache the
   259  	// nodeContext to allow reusing the computations done so far.
   260  	Partial
   261  
   262  	// AllArcs is request only. It must be past Partial, but
   263  	// before recursively resolving arcs.
   264  	AllArcs
   265  
   266  	// EvaluatingArcs indicates that the arcs of the Vertex are currently being
   267  	// evaluated. If this is encountered it indicates a structural cycle.
   268  	// Value does not have to be nil
   269  	EvaluatingArcs
   270  
   271  	// Finalized means that this node is fully evaluated and that the results
   272  	// are save to use without further consideration.
   273  	Finalized
   274  )
   275  
   276  func (s VertexStatus) String() string {
   277  	switch s {
   278  	case Unprocessed:
   279  		return "unprocessed"
   280  	case Evaluating:
   281  		return "evaluating"
   282  	case Partial:
   283  		return "partial"
   284  	case AllArcs:
   285  		return "allarcs"
   286  	case EvaluatingArcs:
   287  		return "evaluatingArcs"
   288  	case Finalized:
   289  		return "finalized"
   290  	default:
   291  		return "unknown"
   292  	}
   293  }
   294  
   295  func (v *Vertex) Status() VertexStatus {
   296  	if v.EvalCount > 0 {
   297  		return EvaluatingArcs
   298  	}
   299  	return v.status
   300  }
   301  
   302  func (v *Vertex) UpdateStatus(s VertexStatus) {
   303  	Assertf(v.status <= s+1, "attempt to regress status from %d to %d", v.Status(), s)
   304  
   305  	if s == Finalized && v.BaseValue == nil {
   306  		// panic("not finalized")
   307  	}
   308  	v.status = s
   309  }
   310  
   311  // Value returns the Value of v without definitions if it is a scalar
   312  // or itself otherwise.
   313  func (v *Vertex) Value() Value {
   314  	switch x := v.BaseValue.(type) {
   315  	case nil:
   316  		return nil
   317  	case *StructMarker, *ListMarker:
   318  		return v
   319  	case Value:
   320  		return x
   321  	default:
   322  		panic(fmt.Sprintf("unexpected type %T", v.BaseValue))
   323  	}
   324  }
   325  
   326  // isUndefined reports whether a vertex does not have a useable BaseValue yet.
   327  func (v *Vertex) isUndefined() bool {
   328  	switch v.BaseValue {
   329  	case nil, cycle:
   330  		return true
   331  	}
   332  	return false
   333  }
   334  
   335  func (x *Vertex) IsConcrete() bool {
   336  	return x.Concreteness() <= Concrete
   337  }
   338  
   339  // IsData reports whether v should be interpreted in data mode. In other words,
   340  // it tells whether optional field matching and non-regular fields, like
   341  // definitions and hidden fields, should be ignored.
   342  func (v *Vertex) IsData() bool {
   343  	return v.isData || len(v.Conjuncts) == 0
   344  }
   345  
   346  // ToDataSingle creates a new Vertex that represents just the regular fields
   347  // of this vertex. Arcs are left untouched.
   348  // It is used by cue.Eval to convert nodes to data on per-node basis.
   349  func (v *Vertex) ToDataSingle() *Vertex {
   350  	w := *v
   351  	w.isData = true
   352  	w.state = nil
   353  	w.status = Finalized
   354  	return &w
   355  }
   356  
   357  // ToDataAll returns a new v where v and all its descendents contain only
   358  // the regular fields.
   359  func (v *Vertex) ToDataAll() *Vertex {
   360  	arcs := make([]*Vertex, 0, len(v.Arcs))
   361  	for _, a := range v.Arcs {
   362  		if a.Label.IsRegular() {
   363  			arcs = append(arcs, a.ToDataAll())
   364  		}
   365  	}
   366  	w := *v
   367  	w.state = nil
   368  	w.status = Finalized
   369  
   370  	w.BaseValue = toDataAll(w.BaseValue)
   371  	w.Arcs = arcs
   372  	w.isData = true
   373  	w.Conjuncts = make([]Conjunct, len(v.Conjuncts))
   374  	// TODO(perf): this is not strictly necessary for evaluation, but it can
   375  	// hurt performance greatly. Drawback is that it may disable ordering.
   376  	for _, s := range w.Structs {
   377  		s.Disable = true
   378  	}
   379  	copy(w.Conjuncts, v.Conjuncts)
   380  	for i, c := range w.Conjuncts {
   381  		if v, _ := c.x.(Value); v != nil {
   382  			w.Conjuncts[i].x = toDataAll(v).(Value)
   383  		}
   384  	}
   385  	return &w
   386  }
   387  
   388  func toDataAll(v BaseValue) BaseValue {
   389  	switch x := v.(type) {
   390  	default:
   391  		return x
   392  
   393  	case *Vertex:
   394  		return x.ToDataAll()
   395  
   396  	// The following cases are always erroneous, but we handle them anyway
   397  	// to avoid issues with the closedness algorithm down the line.
   398  	case *Disjunction:
   399  		d := *x
   400  		d.Values = make([]*Vertex, len(x.Values))
   401  		for i, v := range x.Values {
   402  			d.Values[i] = v.ToDataAll()
   403  		}
   404  		return &d
   405  
   406  	case *Conjunction:
   407  		c := *x
   408  		c.Values = make([]Value, len(x.Values))
   409  		for i, v := range x.Values {
   410  			// This case is okay because the source is of type Value.
   411  			c.Values[i] = toDataAll(v).(Value)
   412  		}
   413  		return &c
   414  	}
   415  }
   416  
   417  // func (v *Vertex) IsEvaluating() bool {
   418  // 	return v.Value == cycle
   419  // }
   420  
   421  func (v *Vertex) IsErr() bool {
   422  	// if v.Status() > Evaluating {
   423  	if _, ok := v.BaseValue.(*Bottom); ok {
   424  		return true
   425  	}
   426  	// }
   427  	return false
   428  }
   429  
   430  func (v *Vertex) Err(c *OpContext, state VertexStatus) *Bottom {
   431  	c.Unify(v, state)
   432  	if b, ok := v.BaseValue.(*Bottom); ok {
   433  		return b
   434  	}
   435  	return nil
   436  }
   437  
   438  // func (v *Vertex) Evaluate()
   439  
   440  func (v *Vertex) Finalize(c *OpContext) {
   441  	// Saving and restoring the error context prevents v from panicking in
   442  	// case the caller did not handle existing errors in the context.
   443  	err := c.errs
   444  	c.errs = nil
   445  	c.Unify(v, Finalized)
   446  	c.errs = err
   447  }
   448  
   449  func (v *Vertex) AddErr(ctx *OpContext, b *Bottom) {
   450  	v.BaseValue = CombineErrors(nil, v.Value(), b)
   451  	v.UpdateStatus(Finalized)
   452  }
   453  
   454  func (v *Vertex) SetValue(ctx *OpContext, state VertexStatus, value BaseValue) *Bottom {
   455  	v.BaseValue = value
   456  	v.UpdateStatus(state)
   457  	return nil
   458  }
   459  
   460  // ToVertex wraps v in a new Vertex, if necessary.
   461  func ToVertex(v Value) *Vertex {
   462  	switch x := v.(type) {
   463  	case *Vertex:
   464  		return x
   465  	default:
   466  		n := &Vertex{
   467  			status:    Finalized,
   468  			BaseValue: x,
   469  		}
   470  		n.AddConjunct(MakeRootConjunct(nil, v))
   471  		return n
   472  	}
   473  }
   474  
   475  // Unwrap returns the possibly non-concrete scalar value of v or nil if v is
   476  // a list, struct or of undefined type.
   477  func Unwrap(v Value) Value {
   478  	x, ok := v.(*Vertex)
   479  	if !ok {
   480  		return v
   481  	}
   482  	// b, _ := x.BaseValue.(*Bottom)
   483  	if n := x.state; n != nil && isCyclePlaceholder(x.BaseValue) {
   484  		if n.errs != nil && !n.errs.IsIncomplete() {
   485  			return n.errs
   486  		}
   487  		if n.scalar != nil {
   488  			return n.scalar
   489  		}
   490  	}
   491  	return x.Value()
   492  }
   493  
   494  // OptionalType is a bit field of the type of optional constraints in use by an
   495  // Acceptor.
   496  type OptionalType int8
   497  
   498  const (
   499  	HasField          OptionalType = 1 << iota // X: T
   500  	HasDynamic                                 // (X): T or "\(X)": T
   501  	HasPattern                                 // [X]: T
   502  	HasComplexPattern                          // anything but a basic type
   503  	HasAdditional                              // ...T
   504  	IsOpen                                     // Defined for all fields
   505  )
   506  
   507  func (v *Vertex) Kind() Kind {
   508  	// This is possible when evaluating comprehensions. It is potentially
   509  	// not known at this time what the type is.
   510  	switch {
   511  	case v.state != nil:
   512  		return v.state.kind
   513  	case v.BaseValue == nil:
   514  		return TopKind
   515  	default:
   516  		return v.BaseValue.Kind()
   517  	}
   518  }
   519  
   520  func (v *Vertex) OptionalTypes() OptionalType {
   521  	var mask OptionalType
   522  	for _, s := range v.Structs {
   523  		mask |= s.OptionalTypes()
   524  	}
   525  	return mask
   526  }
   527  
   528  // IsOptional reports whether a field is explicitly defined as optional,
   529  // as opposed to whether it is allowed by a pattern constraint.
   530  func (v *Vertex) IsOptional(label Feature) bool {
   531  	for _, s := range v.Structs {
   532  		if s.IsOptional(label) {
   533  			return true
   534  		}
   535  	}
   536  	return false
   537  }
   538  
   539  func (v *Vertex) accepts(ok, required bool) bool {
   540  	return ok || (!required && !v.Closed)
   541  }
   542  
   543  func (v *Vertex) IsClosedStruct() bool {
   544  	switch x := v.BaseValue.(type) {
   545  	default:
   546  		return false
   547  
   548  	case *StructMarker:
   549  		if x.NeedClose {
   550  			return true
   551  		}
   552  
   553  	case *Disjunction:
   554  	}
   555  	return v.Closed || isClosed(v)
   556  }
   557  
   558  func (v *Vertex) IsClosedList() bool {
   559  	if x, ok := v.BaseValue.(*ListMarker); ok {
   560  		return !x.IsOpen
   561  	}
   562  	return false
   563  }
   564  
   565  // TODO: return error instead of boolean? (or at least have version that does.)
   566  func (v *Vertex) Accept(ctx *OpContext, f Feature) bool {
   567  	if f.IsInt() {
   568  		switch x := v.BaseValue.(type) {
   569  		case *ListMarker:
   570  			// TODO(perf): use precomputed length.
   571  			if f.Index() < len(v.Elems()) {
   572  				return true
   573  			}
   574  			return !v.IsClosedList()
   575  
   576  		case *Disjunction:
   577  			for _, v := range x.Values {
   578  				if v.Accept(ctx, f) {
   579  					return true
   580  				}
   581  			}
   582  			return false
   583  
   584  		default:
   585  			return v.Kind()&ListKind != 0
   586  		}
   587  	}
   588  
   589  	if k := v.Kind(); k&StructKind == 0 && f.IsString() && f != AnyLabel {
   590  		// If the value is bottom, we may not really know if this used to
   591  		// be a struct.
   592  		if k != BottomKind || len(v.Structs) == 0 {
   593  			return false
   594  		}
   595  	}
   596  
   597  	if f.IsHidden() || !v.IsClosedStruct() || v.Lookup(f) != nil {
   598  		return true
   599  	}
   600  
   601  	// TODO(perf): collect positions in error.
   602  	defer ctx.ReleasePositions(ctx.MarkPositions())
   603  
   604  	return v.accepts(Accept(ctx, v, f))
   605  }
   606  
   607  // MatchAndInsert finds the conjuncts for optional fields, pattern
   608  // constraints, and additional constraints that match f and inserts them in
   609  // arc. Use f is 0 to match all additional constraints only.
   610  func (v *Vertex) MatchAndInsert(ctx *OpContext, arc *Vertex) {
   611  	if !v.Accept(ctx, arc.Label) {
   612  		return
   613  	}
   614  
   615  	// Go backwards to simulate old implementation.
   616  	for i := len(v.Structs) - 1; i >= 0; i-- {
   617  		s := v.Structs[i]
   618  		if s.Disable {
   619  			continue
   620  		}
   621  		s.MatchAndInsert(ctx, arc)
   622  	}
   623  }
   624  
   625  func (v *Vertex) IsList() bool {
   626  	_, ok := v.BaseValue.(*ListMarker)
   627  	return ok
   628  }
   629  
   630  // Lookup returns the Arc with label f if it exists or nil otherwise.
   631  func (v *Vertex) Lookup(f Feature) *Vertex {
   632  	for _, a := range v.Arcs {
   633  		if a.Label == f {
   634  			return a
   635  		}
   636  	}
   637  	return nil
   638  }
   639  
   640  // Elems returns the regular elements of a list.
   641  func (v *Vertex) Elems() []*Vertex {
   642  	// TODO: add bookkeeping for where list arcs start and end.
   643  	a := make([]*Vertex, 0, len(v.Arcs))
   644  	for _, x := range v.Arcs {
   645  		if x.Label.IsInt() {
   646  			a = append(a, x)
   647  		}
   648  	}
   649  	return a
   650  }
   651  
   652  // GetArc returns a Vertex for the outgoing arc with label f. It creates and
   653  // ads one if it doesn't yet exist.
   654  func (v *Vertex) GetArc(c *OpContext, f Feature) (arc *Vertex, isNew bool) {
   655  	arc = v.Lookup(f)
   656  	if arc == nil {
   657  		for _, a := range v.state.usedArcs {
   658  			if a.Label == f {
   659  				arc = a
   660  				v.Arcs = append(v.Arcs, arc)
   661  				isNew = true
   662  				if c.nonMonotonicInsertNest > 0 {
   663  					a.nonMonotonicInsertGen = c.nonMonotonicGeneration
   664  				}
   665  				break
   666  			}
   667  		}
   668  	}
   669  	if arc == nil {
   670  		arc = &Vertex{Parent: v, Label: f}
   671  		v.Arcs = append(v.Arcs, arc)
   672  		isNew = true
   673  		if c.nonMonotonicInsertNest > 0 {
   674  			arc.nonMonotonicInsertGen = c.nonMonotonicGeneration
   675  		}
   676  	}
   677  	if c.nonMonotonicInsertNest == 0 {
   678  		arc.nonMonotonicInsertGen = 0
   679  	}
   680  	return arc, isNew
   681  }
   682  
   683  func (v *Vertex) Source() ast.Node {
   684  	if v != nil {
   685  		if b, ok := v.BaseValue.(Value); ok {
   686  			return b.Source()
   687  		}
   688  	}
   689  	return nil
   690  }
   691  
   692  // AddConjunct adds the given Conjuncts to v if it doesn't already exist.
   693  func (v *Vertex) AddConjunct(c Conjunct) *Bottom {
   694  	if v.BaseValue != nil {
   695  		// TODO: investigate why this happens at all. Removing it seems to
   696  		// change the order of fields in some cases.
   697  		//
   698  		// This is likely a bug in the evaluator and should not happen.
   699  		return &Bottom{Err: errors.Newf(token.NoPos, "cannot add conjunct")}
   700  	}
   701  	v.addConjunct(c)
   702  	return nil
   703  }
   704  
   705  func (v *Vertex) addConjunct(c Conjunct) {
   706  	for _, x := range v.Conjuncts {
   707  		if x == c {
   708  			return
   709  		}
   710  	}
   711  	v.Conjuncts = append(v.Conjuncts, c)
   712  }
   713  
   714  func (v *Vertex) AddStruct(s *StructLit, env *Environment, ci CloseInfo) *StructInfo {
   715  	info := StructInfo{
   716  		StructLit: s,
   717  		Env:       env,
   718  		CloseInfo: ci,
   719  	}
   720  	for _, t := range v.Structs {
   721  		if *t == info {
   722  			return t
   723  		}
   724  	}
   725  	t := &info
   726  	v.Structs = append(v.Structs, t)
   727  	return t
   728  }
   729  
   730  // Path computes the sequence of Features leading from the root to of the
   731  // instance to this Vertex.
   732  //
   733  // NOTE: this is for debugging purposes only.
   734  func (v *Vertex) Path() []Feature {
   735  	return appendPath(nil, v)
   736  }
   737  
   738  func appendPath(a []Feature, v *Vertex) []Feature {
   739  	if v.Parent == nil {
   740  		return a
   741  	}
   742  	a = appendPath(a, v.Parent)
   743  	if v.Label != 0 {
   744  		// A Label may be 0 for programmatically inserted nodes.
   745  		a = append(a, v.Label)
   746  	}
   747  	return a
   748  }
   749  
   750  // An Conjunct is an Environment-Expr pair. The Environment is the starting
   751  // point for reference lookup for any reference contained in X.
   752  type Conjunct struct {
   753  	Env *Environment
   754  	x   Node
   755  
   756  	// CloseInfo is a unique number that tracks a group of conjuncts that need
   757  	// belong to a single originating definition.
   758  	CloseInfo CloseInfo
   759  }
   760  
   761  // TODO(perf): replace with composite literal if this helps performance.
   762  
   763  // MakeRootConjunct creates a conjunct from the given environment and node.
   764  // It panics if x cannot be used as an expression.
   765  func MakeRootConjunct(env *Environment, x Node) Conjunct {
   766  	return MakeConjunct(env, x, CloseInfo{})
   767  }
   768  
   769  func MakeConjunct(env *Environment, x Node, id CloseInfo) Conjunct {
   770  	if env == nil {
   771  		// TODO: better is to pass one.
   772  		env = &Environment{}
   773  	}
   774  	switch x.(type) {
   775  	case Expr, interface{ expr() Expr }:
   776  	default:
   777  		panic(fmt.Sprintf("invalid Node type %T", x))
   778  	}
   779  	return Conjunct{env, x, id}
   780  }
   781  
   782  func (c *Conjunct) Source() ast.Node {
   783  	return c.x.Source()
   784  }
   785  
   786  func (c *Conjunct) Field() Node {
   787  	return c.x
   788  }
   789  
   790  func (c *Conjunct) Expr() Expr {
   791  	switch x := c.x.(type) {
   792  	case Expr:
   793  		return x
   794  	case interface{ expr() Expr }:
   795  		return x.expr()
   796  	default:
   797  		panic("unreachable")
   798  	}
   799  }