cuelang.org/go@v0.13.0/internal/core/adt/unify.go (about)

     1  // Copyright 2023 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  	"cuelang.org/go/cue/token"
    21  )
    22  
    23  // TODO(mpvl): perhaps conjunctsProcessed is a better name for this.
    24  func (v *Vertex) isInitialized() bool {
    25  	return v.status == finalized || (v.state != nil && v.state.isInitialized)
    26  }
    27  
    28  func (n *nodeContext) assertInitialized() {
    29  	if n != nil && n.ctx.isDevVersion() {
    30  		if v := n.node; !v.isInitialized() {
    31  			panic(fmt.Sprintf("vertex %p not initialized", v))
    32  		}
    33  	}
    34  }
    35  
    36  // isInProgress reports whether v is in the midst of being evaluated. This means
    37  // that conjuncts have been scheduled, but that it has not been finalized.
    38  func (v *Vertex) isInProgress() bool {
    39  	return v.status != finalized && v.state != nil && v.state.isInitialized
    40  }
    41  
    42  func (v *Vertex) getBareState(c *OpContext) *nodeContext {
    43  	if v.status == finalized { // TODO: use BaseValue != nil
    44  		return nil
    45  	}
    46  	if v.state == nil {
    47  		v.state = c.newNodeContext(v)
    48  		v.state.initBare()
    49  		v.state.refCount = 1
    50  	}
    51  
    52  	// An additional refCount for the current user.
    53  	v.state.refCount += 1
    54  
    55  	// TODO: see if we can get rid of ref counting after new evaluator is done:
    56  	// the recursive nature of the new evaluator should make this unnecessary.
    57  
    58  	return v.state
    59  }
    60  
    61  func (v *Vertex) getState(c *OpContext) *nodeContext {
    62  	s := v.getBareState(c)
    63  	if s != nil && !s.isInitialized {
    64  		s.scheduleConjuncts()
    65  	}
    66  	return s
    67  }
    68  
    69  // initNode initializes a nodeContext for the evaluation of the given Vertex.
    70  func (n *nodeContext) initBare() {
    71  	v := n.node
    72  	if v.Parent != nil && v.Parent.state != nil {
    73  		v.state.depth = v.Parent.state.depth + 1
    74  		n.blockOn(allAncestorsProcessed)
    75  	}
    76  
    77  	n.blockOn(scalarKnown | listTypeKnown | arcTypeKnown)
    78  
    79  	if v.Label.IsDef() {
    80  		v.ClosedRecursive = true
    81  	}
    82  
    83  	if v.Parent != nil {
    84  		if v.Parent.ClosedRecursive {
    85  			v.ClosedRecursive = true
    86  		}
    87  	}
    88  }
    89  
    90  func (n *nodeContext) scheduleConjuncts() {
    91  	n.isInitialized = true
    92  
    93  	v := n.node
    94  	ctx := n.ctx
    95  
    96  	ctx.stats.Unifications++
    97  
    98  	// Set the cache to a cycle error to ensure a cyclic reference will result
    99  	// in an error if applicable. A cyclic error may be ignored for
   100  	// non-expression references. The cycle error may also be removed as soon
   101  	// as there is evidence what a correct value must be, but before all
   102  	// validation has taken place.
   103  	//
   104  	// TODO(cycle): having a more recursive algorithm would make this
   105  	// special cycle handling unnecessary.
   106  	v.BaseValue = cycle
   107  
   108  	defer ctx.PopArc(ctx.PushArc(v))
   109  
   110  	for i, c := range v.Conjuncts {
   111  		_ = i // for debugging purposes
   112  		ci := c.CloseInfo
   113  		ci = ctx.combineCycleInfo(ci)
   114  		n.scheduleConjunct(c, ci)
   115  	}
   116  }
   117  
   118  // TODO(evalv3): consider not returning a result at all.
   119  //
   120  //	func (v *Vertex) unify@(c *OpContext, needs condition, mode runMode) bool {
   121  //		return v.unifyC(c, needs, mode, true)
   122  //	}
   123  func (v *Vertex) unify(c *OpContext, needs condition, mode runMode, checkTypos bool) bool {
   124  	if c.LogEval > 0 {
   125  		defer c.Un(c.Indentf(v, "UNIFY(%x, %v)", needs, mode))
   126  	}
   127  
   128  	// TODO: investigate whether we still need this mechanism.
   129  	//
   130  	// This has been disabled to fix Issue #3709. This was added in lieu of a
   131  	// proper depth detecting mechanism. This has been implemented now, but
   132  	// we keep this around to investigate certain edge cases, such as
   133  	// depth checking across inline vertices.
   134  	//
   135  	// if c.evalDepth == 0 {
   136  	// 	defer func() {
   137  	// 		// This loop processes nodes that need to be evaluated, but should be
   138  	// 		// evaluated outside of the stack to avoid structural cycle detection.
   139  	// 		// See comment at toFinalize.
   140  	// 		a := c.toFinalize
   141  	// 		c.toFinalize = c.toFinalize[:0]
   142  	// 		for _, x := range a {
   143  	// 			x.Finalize(c)
   144  	// 		}
   145  	// 	}()
   146  	// }
   147  
   148  	if mode == ignore {
   149  		return false
   150  	}
   151  
   152  	// Note that the state of a node can be removed before the node is.
   153  	// This happens with the close builtin, for instance.
   154  	// See TestFromAPI in pkg export.
   155  	// TODO(evalv3): find something more principled.
   156  	n := v.getState(c)
   157  	if n == nil {
   158  		v.status = finalized
   159  		return true // already completed
   160  	}
   161  
   162  	// TODO(perf): reintroduce freeing once we have the lifetime under control.
   163  	// Right now this is not managed anyway, so we prevent bugs by disabling it.
   164  	// defer n.free()
   165  
   166  	// Typically a node processes all conjuncts before processing its fields.
   167  	// So this condition is very likely to trigger. If for some reason the
   168  	// parent has not been processed yet, we could attempt to process more
   169  	// of its tasks to increase the chances of being able to find the
   170  	// information we are looking for here. For now we just continue as is.
   171  	//
   172  	// For dynamic nodes, the parent only exists to provide a path context.
   173  	//
   174  	// Note that if mode is final, we will guarantee that the conditions for
   175  	// this if clause are met down the line. So we assume this is already the
   176  	// case and set the signal accordingly if so.
   177  	if !v.Rooted() || v.Parent.allChildConjunctsKnown() || mode == finalize {
   178  		n.signal(allAncestorsProcessed)
   179  	}
   180  
   181  	nodeOnlyNeeds := needs &^ (subFieldsProcessed)
   182  
   183  	if v.BaseValue == nil {
   184  		v.BaseValue = cycle
   185  	}
   186  	n.updateScalar()
   187  	if nodeOnlyNeeds == (scalarKnown|arcTypeKnown) && n.meets(nodeOnlyNeeds) {
   188  		return true
   189  	}
   190  
   191  	// Detect a self-reference: if this node is under evaluation at the same
   192  	// evaluation depth, this means that we have a self-reference, possibly
   193  	// through an expression. As long as there is no request to process arcs or
   194  	// finalize the value, we can and should stop processing here to avoid
   195  	// spurious cycles.
   196  
   197  	if v.status == evaluating && v.state.evalDepth == c.evalDepth {
   198  		switch mode {
   199  		case finalize:
   200  			// We will force completion below.
   201  		case yield:
   202  			// TODO: perhaps add to queue in some condition.
   203  		default:
   204  			if needs&fieldSetKnown == 0 {
   205  				return false
   206  			}
   207  		}
   208  	}
   209  
   210  	v.status = evaluating
   211  
   212  	defer n.unmarkDepth(n.markDepth())
   213  
   214  	if n.node.ArcType == ArcPending {
   215  		// forcefully do an early recursive evaluation to decide the state
   216  		// of the arc. See https://cuelang.org/issue/3621.
   217  		n.process(pendingKnown, yield)
   218  		if n.node.ArcType == ArcPending {
   219  			for _, a := range n.node.Arcs {
   220  				a.unify(c, needs, attemptOnly, checkTypos)
   221  			}
   222  		}
   223  		// TODO(evalv3): do we need this? Error messages are slightly better,
   224  		// but adding leads to Issue #3941.
   225  		// n.completePending(yield)
   226  	}
   227  
   228  	n.process(nodeOnlyNeeds, mode)
   229  
   230  	if n.node.ArcType != ArcPending &&
   231  		n.meets(allAncestorsProcessed) &&
   232  		len(n.tasks) == n.taskPos {
   233  		n.signal(arcTypeKnown)
   234  	}
   235  
   236  	defer c.PopArc(c.PushArc(v))
   237  
   238  	w := v.DerefDisjunct()
   239  	if w != v {
   240  		// Should resolve with dereference.
   241  		v.ClosedRecursive = w.ClosedRecursive
   242  		v.status = w.status
   243  		v.ChildErrors = CombineErrors(nil, v.ChildErrors, w.ChildErrors)
   244  		v.Arcs = nil
   245  		return w.state.meets(needs)
   246  	}
   247  	n.updateScalar()
   248  
   249  	if n.aStruct != nil {
   250  		n.updateNodeType(StructKind, n.aStruct, n.aStructID)
   251  	}
   252  
   253  	// First process all but the subfields.
   254  	switch {
   255  	case n.meets(nodeOnlyNeeds):
   256  		// pass through next phase.
   257  	case mode != finalize:
   258  		// TODO: disjunctions may benefit from evaluation as much prematurely
   259  		// as possible, as this increases the chances of premature failure.
   260  		// We should consider doing a recursive "attemptOnly" evaluation here.
   261  		return false
   262  	}
   263  
   264  	if n.isShared {
   265  		if isCyclePlaceholder(n.origBaseValue) {
   266  			n.origBaseValue = nil
   267  		}
   268  	} else if isCyclePlaceholder(n.node.BaseValue) {
   269  		n.node.BaseValue = nil
   270  	}
   271  	if !n.isShared {
   272  		// TODO(sharewithval): allow structure sharing if we only have validator
   273  		// and references.
   274  		// TODO: rewrite to use mode when we get rid of old evaluator.
   275  		state := finalized
   276  		n.validateValue(state)
   277  	}
   278  
   279  	if v, ok := n.node.BaseValue.(*Vertex); ok && n.shareCycleType == NoCycle {
   280  		if n.ctx.hasDepthCycle(v) {
   281  			n.reportCycleError()
   282  			return true
   283  		}
   284  		// We unify here to proactively detect cycles. We do not need to,
   285  		// nor should we, if have have already found one.
   286  		v.unify(n.ctx, needs, mode, checkTypos)
   287  	}
   288  
   289  	// At this point, no more conjuncts will be added, so we could decrement
   290  	// the notification counters.
   291  
   292  	switch {
   293  	case n.completed&subFieldsProcessed != 0:
   294  		// done
   295  
   296  	case needs&subFieldsProcessed != 0:
   297  		switch {
   298  		case assertStructuralCycleV3(n):
   299  
   300  		case n.node.status == finalized:
   301  			// There is no need to recursively process if the node is already
   302  			// finalized. This can happen if there was an error, for instance.
   303  			// This may drop a structural cycle error, but as long as the node
   304  			// already is erroneous, that is fine. It is probably possible to
   305  			// skip more processing if the node is already finalized.
   306  
   307  		// TODO: consider bailing on error if n.errs != nil.
   308  		// At the very least, no longer propagate typo errors if this node
   309  		// is erroneous.
   310  		case n.kind == BottomKind:
   311  		case n.completeAllArcs(needs, mode, checkTypos):
   312  		}
   313  
   314  		if mode == finalize {
   315  			n.signal(subFieldsProcessed)
   316  		}
   317  
   318  		if v.BaseValue == nil {
   319  			// TODO: this seems to not be possible. Possibly remove.
   320  			state := finalized
   321  			v.BaseValue = n.getValidators(state)
   322  		}
   323  		if v := n.node.Value(); v != nil && IsConcrete(v) {
   324  			// Ensure that checks are not run again when this value is used
   325  			// in a validator.
   326  			checks := n.checks
   327  			n.checks = n.checks[:0]
   328  			for _, v := range checks {
   329  				// TODO(errors): make Validate return bottom and generate
   330  				// optimized conflict message. Also track and inject IDs
   331  				// to determine origin location.s
   332  				if b := c.Validate(v, n.node); b != nil {
   333  					n.addBottom(b)
   334  				}
   335  			}
   336  		}
   337  
   338  	case needs&fieldSetKnown != 0:
   339  		n.evalArcTypes(mode)
   340  	}
   341  
   342  	if err := n.getErr(); err != nil {
   343  		n.errs = nil
   344  		if b := n.node.Bottom(); b != nil {
   345  			err = CombineErrors(nil, b, err)
   346  		}
   347  		n.setBaseValue(err)
   348  	}
   349  
   350  	n.finalizeDisjunctions()
   351  
   352  	if mode == attemptOnly {
   353  		return n.meets(needs)
   354  	}
   355  
   356  	if mask := n.completed & needs; mask != 0 {
   357  		// TODO: phase3: validation
   358  		n.signal(mask)
   359  	}
   360  
   361  	w = v.DerefValue() // Dereference anything, including shared nodes.
   362  	if w != v {
   363  		// Clear value fields that are now referred to in the dereferenced
   364  		// value (w).
   365  		v.ChildErrors = nil
   366  		v.Arcs = nil
   367  
   368  		if n.completed&(subFieldsProcessed) == 0 {
   369  			// Ensure the shared node is processed to the requested level. This is
   370  			// typically needed for scalar values.
   371  			if w.status == unprocessed {
   372  				w.unify(c, needs, mode, false)
   373  			}
   374  
   375  			return n.meets(needs)
   376  		}
   377  
   378  		// Set control fields that are referenced without dereferencing.
   379  		if w.ClosedRecursive {
   380  			v.ClosedRecursive = true
   381  		}
   382  		// NOTE: setting ClosedNonRecursive is not necessary, as it is
   383  		// handled by scheduleValue.
   384  		if w.HasEllipsis {
   385  			v.HasEllipsis = true
   386  		}
   387  
   388  		v.status = w.status
   389  
   390  		n.finalizeSharing()
   391  
   392  		// TODO: find a more principled way to catch this cycle and avoid this
   393  		// check.
   394  		if n.hasAncestorV3(w) {
   395  			n.reportCycleError()
   396  			return true
   397  		}
   398  
   399  		// Ensure that shared nodes comply to the same requirements as we
   400  		// need for the current node.
   401  		w.unify(c, needs, mode, checkTypos)
   402  
   403  		return true
   404  	}
   405  
   406  	if n.completed&(subFieldsProcessed) == 0 {
   407  		return n.meets(needs)
   408  	}
   409  
   410  	// TODO: adding this is wrong, but it should not cause the snippet below
   411  	// to hang. Investigate.
   412  	// v.Closed = v.cc.isClosed
   413  	//
   414  	// This hangs:
   415  	// issue1940: {
   416  	// 	#T: ["a", #T] | ["c", #T] | ["d", [...#T]]
   417  	// 	#A: t: #T
   418  	// 	#B: x: #A
   419  	// 	#C: #B
   420  	// 	#C: x: #A
   421  	// }
   422  
   423  	// validationCompleted
   424  	// The next piece of code used to address the following case
   425  	// (order matters)
   426  	//
   427  	// 		c1: c: [string]: f2
   428  	// 		f2: c1
   429  	// 		Also: cycle/issue990
   430  	//
   431  	// However, with recent changes, it no longer matters. Simultaneously,
   432  	// this causes a hang in the following case:
   433  	//
   434  	// 		_self: x: [...and(x)]
   435  	// 		_self
   436  	// 		x: [1]
   437  	//
   438  	// For this reason we disable it now. It may be the case that we need
   439  	// to enable it for computing disjunctions.
   440  	//
   441  	n.incDepth()
   442  	defer n.decDepth()
   443  
   444  	if pc := n.node.PatternConstraints; pc != nil {
   445  		for _, c := range pc.Pairs {
   446  			c.Constraint.unify(n.ctx, allKnown, attemptOnly, checkTypos)
   447  		}
   448  	}
   449  
   450  	// TODO: find more strategic place to set ClosedRecursive and get rid
   451  	// of helper fields.
   452  	blockClose := n.hasTop
   453  	if n.hasStruct {
   454  		blockClose = false
   455  	}
   456  	if n.hasOpenValidator {
   457  		blockClose = true
   458  	}
   459  	if n.isDef && !blockClose {
   460  		n.node.ClosedRecursive = true
   461  	}
   462  
   463  	n.node.updateStatus(finalized)
   464  
   465  	if checkTypos {
   466  		n.checkTypos()
   467  	}
   468  
   469  	return n.meets(needs)
   470  }
   471  
   472  // Once returning, all arcs plus conjuncts that can be known are known.
   473  //
   474  // Proof:
   475  //   - if there is a cycle, all completeNodeConjuncts will be called
   476  //     repeatedly for all nodes in this cycle, and all tasks on the cycle
   477  //     will have run at least once.
   478  //   - any tasks that were blocking on values on this circle to be completed
   479  //     will thus have to be completed at some point in time if they can.
   480  //   - any tasks that were blocking on values outside of this ring will have
   481  //     initiated its own execution, which is either not cyclic, and thus
   482  //     completes, or is on a different cycle, in which case it completes as
   483  //     well.
   484  //
   485  // Goal:
   486  // - complete notifications
   487  // - decrement reference counts for root and notify.
   488  // NOT:
   489  // - complete value. That is reserved for Unify.
   490  func (n *nodeContext) completeNodeTasks(mode runMode) {
   491  	if n.ctx.LogEval > 0 {
   492  		defer n.ctx.Un(n.ctx.Indentf(n.node, "(%v)", mode))
   493  	}
   494  
   495  	n.assertInitialized()
   496  
   497  	if n.isCompleting > 0 {
   498  		return
   499  	}
   500  	n.isCompleting++
   501  	defer func() {
   502  		n.isCompleting--
   503  	}()
   504  
   505  	v := n.node
   506  
   507  	if !v.Label.IsLet() {
   508  		if p := v.Parent; p != nil && p.state != nil {
   509  			if !v.IsDynamic && n.completed&allAncestorsProcessed == 0 {
   510  				p.state.completeNodeTasks(mode)
   511  			}
   512  		}
   513  	}
   514  
   515  	if v.IsDynamic || v.Label.IsLet() || v.Parent.allChildConjunctsKnown() {
   516  		n.signal(allAncestorsProcessed)
   517  	}
   518  
   519  	if len(n.scheduler.tasks) != n.scheduler.taskPos {
   520  		// TODO: do we need any more requirements here?
   521  		const needs = valueKnown | fieldConjunctsKnown
   522  
   523  		n.process(needs, mode)
   524  		n.updateScalar()
   525  	}
   526  
   527  	// As long as ancestors are not processed, it is still possible for
   528  	// conjuncts to be inserted. Until that time, it is not okay to decrement
   529  	// theroot. It is not necessary to wait on tasks to complete, though,
   530  	// as pending tasks will have their own dependencies on root, meaning it
   531  	// is safe to decrement here.
   532  	if !n.meets(allAncestorsProcessed) && !n.node.Label.IsLet() && mode != finalize {
   533  		return
   534  	}
   535  }
   536  
   537  func (n *nodeContext) updateScalar() {
   538  	// Set BaseValue to scalar, but only if it was not set before. Most notably,
   539  	// errors should not be discarded.
   540  	if n.scalar != nil && (!n.node.IsErr() || isCyclePlaceholder(n.node.BaseValue)) {
   541  		if v, ok := n.node.BaseValue.(*Vertex); !ok || !v.IsDisjunct {
   542  			n.setBaseValue(n.scalar)
   543  		}
   544  		n.signal(scalarKnown)
   545  	}
   546  }
   547  
   548  func (n *nodeContext) completeAllArcs(needs condition, mode runMode, checkTypos bool) bool {
   549  	if n.underlying != nil {
   550  		// References within the disjunct may end up referencing the layer that
   551  		// this node overlays. Also for these nodes we want to be able to detect
   552  		// structural cycles early. For this reason, we also set the
   553  		// evaluatingArcs status in the underlying layer.
   554  		//
   555  		// TODO: for now, this seems not necessary. Moreover, this will cause
   556  		// benchmarks/cycle to display a spurious structural cycle. But it
   557  		// shortens some of the structural cycle depths. So consider using this.
   558  		//
   559  		// status := n.underlying.status
   560  		// n.underlying.updateStatus(evaluatingArcs) defer func() {
   561  		// n.underlying.status = status }()
   562  	}
   563  
   564  	// TODO: this should only be done if n is not currently running tasks.
   565  	// Investigate how to work around this.
   566  	n.completeNodeTasks(finalize)
   567  
   568  	n.incDepth()
   569  	defer n.decDepth()
   570  
   571  	// TODO: do something more principled here.s
   572  	if n.hasDisjunction {
   573  		checkTypos = false
   574  	}
   575  
   576  	// XXX(0.7): only set success if needs complete arcs.
   577  	success := true
   578  	// Visit arcs recursively to validate and compute error. Use index instead
   579  	// of range in case the Arcs grows during processing.
   580  	for arcPos := 0; arcPos < len(n.node.Arcs); arcPos++ {
   581  		a := n.node.Arcs[arcPos]
   582  		// TODO: Consider skipping lets.
   583  
   584  		if !a.unify(n.ctx, needs, mode, checkTypos) {
   585  			success = false
   586  		}
   587  
   588  		// At this point we need to ensure that all notification cycles
   589  		// for Arc a have been processed.
   590  
   591  		if a.ArcType == ArcPending {
   592  			// TODO: cancel tasks?
   593  			// TODO: is this ever run? Investigate once new evaluator work is
   594  			// complete.
   595  			a.ArcType = ArcNotPresent
   596  			continue
   597  		}
   598  
   599  		// TODO: harmonize this error with "cannot combine"
   600  		switch {
   601  		case a.ArcType > ArcRequired, !a.Label.IsString():
   602  		case n.kind&StructKind == 0:
   603  			if !n.node.IsErr() && !a.IsErr() {
   604  				n.reportFieldMismatch(pos(a.Value()), nil, a.Label, n.node.Value())
   605  			}
   606  			// case !wasVoid:
   607  			// case n.kind == TopKind:
   608  			// 	// Theoretically it may be possible that a "void" arc references
   609  			// 	// this top value where it really should have been a struct. One
   610  			// 	// way to solve this is to have two passes over the arcs, where
   611  			// 	// the first pass additionally analyzes whether comprehensions
   612  			// 	// will yield values and "un-voids" an arc ahead of the rest.
   613  			// 	//
   614  			// 	// At this moment, though, I fail to see a possibility to create
   615  			// 	// faulty CUE using this mechanism, though. At most error
   616  			// 	// messages are a bit unintuitive. This may change once we have
   617  			// 	// functionality to reflect on types.
   618  			// 	if _, ok := n.node.BaseValue.(*Bottom); !ok {
   619  			// 		n.node.BaseValue = &StructMarker{}
   620  			// 		n.kind = StructKind
   621  			// 	}
   622  		}
   623  	}
   624  
   625  	k := 0
   626  	for _, a := range n.node.Arcs {
   627  		if a.ArcType != ArcNotPresent {
   628  			n.node.Arcs[k] = a
   629  			k++
   630  		}
   631  	}
   632  	n.node.Arcs = n.node.Arcs[:k]
   633  
   634  	for _, a := range n.node.Arcs {
   635  		// Errors are allowed in let fields. Handle errors and failure to
   636  		// complete accordingly.
   637  		if !a.Label.IsLet() && a.ArcType <= ArcRequired {
   638  			a := a.DerefValue()
   639  			if err := a.Bottom(); err != nil {
   640  				n.AddChildError(err)
   641  			}
   642  			success = true // other arcs are irrelevant
   643  		}
   644  	}
   645  
   646  	// TODO: perhaps this code can go once we have builtins for comparing to
   647  	// bottom.
   648  	for _, c := range n.postChecks {
   649  		ctx := n.ctx
   650  		f := ctx.PushState(c.env, c.expr.Source())
   651  
   652  		v := ctx.evalState(c.expr, oldOnly(finalized))
   653  		v, _ = ctx.getDefault(v)
   654  		v = Unwrap(v)
   655  
   656  		switch _, isError := v.(*Bottom); {
   657  		case isError == c.expectError:
   658  		default:
   659  			n.node.AddErr(ctx, &Bottom{
   660  				Src:  c.expr.Source(),
   661  				Code: CycleError,
   662  				Node: n.node,
   663  				Err: ctx.NewPosf(pos(c.expr),
   664  					"circular dependency in evaluation of conditionals: %v changed after evaluation",
   665  					ctx.Str(c.expr)),
   666  			})
   667  		}
   668  
   669  		ctx.PopState(f)
   670  	}
   671  
   672  	// This should be called after all arcs have been processed, because
   673  	// whether sharing is possible or not may depend on how arcs with type
   674  	// ArcPending will resolve.
   675  	n.finalizeSharing()
   676  
   677  	// Strip struct literals that were not initialized and are not part
   678  	// of the output.
   679  	//
   680  	// TODO(perf): we could keep track if any such structs exist and only
   681  	// do this removal if there is a change of shrinking the list.
   682  	k = 0
   683  	for _, s := range n.node.Structs {
   684  		if s.initialized {
   685  			n.node.Structs[k] = s
   686  			k++
   687  		}
   688  	}
   689  	n.node.Structs = n.node.Structs[:k]
   690  
   691  	// TODO: This seems to be necessary, but enables structural cycles.
   692  	// Evaluator whether we still need this.
   693  	//
   694  	// pc := n.node.PatternConstraints
   695  	// if pc == nil {
   696  	// 	return success
   697  	// }
   698  	// for _, c := range pc.Pairs {
   699  	// 	c.Constraint.Finalize(n.ctx)
   700  	// }
   701  
   702  	return success
   703  }
   704  
   705  // completePending determines if n is pending. In order to do so, it must
   706  // recursively find any descendents with unresolved comprehensions. Note that
   707  // it is currently possible for arcs with unresolved comprehensions to not be
   708  // marked as pending. Consider this example (from issue 3708):
   709  //
   710  //	out: people.bob.kind
   711  //	people: [string]: {
   712  //		kind:  "person"
   713  //		name?: string
   714  //	}
   715  //	if true {
   716  //		people: bob: name: "Bob"
   717  //	}
   718  //
   719  // In this case, the pattern constraint inserts fields into 'bob', which then
   720  // marks 'name' as not pending. However, for 'people' to become non-pending,
   721  // the comprehension associated with field 'name' still needs to be evaluated.
   722  //
   723  // For this reason, this method does not check whether 'n' is pending.
   724  //
   725  // TODO(evalv4): consider making pending not an arc state, but rather a
   726  // separate mode. This will allow us to descend with more precision to only
   727  // visit arcs that still need to be resolved.
   728  func (n *nodeContext) completePending(mode runMode) {
   729  	for _, a := range n.node.Arcs {
   730  		state := a.getState(n.ctx)
   731  		if state != nil {
   732  			state.completePending(mode)
   733  		}
   734  	}
   735  	n.process(pendingKnown, mode)
   736  }
   737  
   738  func (n *nodeContext) evalArcTypes(mode runMode) {
   739  	for _, a := range n.node.Arcs {
   740  		if a.ArcType != ArcPending {
   741  			continue
   742  		}
   743  		a.unify(n.ctx, arcTypeKnown, mode, false)
   744  		// Ensure the arc is processed up to the desired level
   745  		if a.ArcType == ArcPending {
   746  			// TODO: cancel tasks?
   747  			a.ArcType = ArcNotPresent
   748  		}
   749  	}
   750  }
   751  
   752  func root(v *Vertex) *Vertex {
   753  	for v.Parent != nil {
   754  		v = v.Parent
   755  	}
   756  	return v
   757  }
   758  
   759  func (v *Vertex) lookup(c *OpContext, pos token.Pos, f Feature, flags combinedFlags) *Vertex {
   760  	task := c.current()
   761  	needs := flags.conditions()
   762  	runMode := flags.runMode()
   763  
   764  	v = v.DerefValue()
   765  
   766  	if c.LogEval > 0 {
   767  		c.Logf(c.vertex, "LOOKUP %v", f)
   768  	}
   769  
   770  	state := v.getState(c)
   771  	if state != nil {
   772  		// If the scheduler associated with this vertex was already running,
   773  		// it means we have encountered a cycle. In that case, we allow to
   774  		// proceed with partial data, in which case a "pending" arc will be
   775  		// created to be completed later.
   776  
   777  		// Propagate error if the error is from a different package. This
   778  		// compensates for the fact that we do not fully evaluate the package.
   779  		if state.hasErr() {
   780  			err := state.getErr()
   781  			if err != nil && err.Node != nil && root(err.Node) != root(v) {
   782  				c.AddBottom(err)
   783  			}
   784  		}
   785  
   786  		// A lookup counts as new structure. See the commend in Section
   787  		// "Lookups in inline cycles" in cycle.go.
   788  		// TODO: this seems no longer necessary and setting this will cause some
   789  		// hangs. Investigate.
   790  		// state.hasNonCycle = true
   791  
   792  		// TODO: ideally this should not be run at this point. Consider under
   793  		// which circumstances this is still necessary, and at least ensure
   794  		// this will not be run if node v currently has a running task.
   795  		state.completeNodeTasks(attemptOnly)
   796  	}
   797  
   798  	// TODO: remove because unnecessary?
   799  	if task != nil && task.state != taskRUNNING {
   800  		return nil // abort, task is blocked or terminated in a cycle.
   801  	}
   802  
   803  	// TODO: verify lookup types.
   804  
   805  	arc := v.LookupRaw(f)
   806  	// We leave further dereferencing to the caller, but we do dereference for
   807  	// the remainder of this function to be able to check the status.
   808  	arcReturn := arc
   809  	if arc != nil {
   810  		arc = arc.DerefNonRooted()
   811  		// TODO(perf): NonRooted is the minimum, but consider doing more.
   812  		// arc = arc.DerefValue()
   813  	}
   814  
   815  	// TODO: clean up this logic:
   816  	// - signal arcTypeKnown when ArcMember or ArcNotPresent is set,
   817  	//   similarly to scalarKnown.
   818  	// - make it clear we want to yield if it is now known if a field exists.
   819  
   820  	var arcState *nodeContext
   821  	switch {
   822  	case arc != nil:
   823  		if arc.ArcType == ArcMember {
   824  			return arcReturn
   825  		}
   826  		arcState = arc.getState(c)
   827  
   828  	case state == nil || state.meets(needTasksDone):
   829  		// This arc cannot exist.
   830  		v.reportFieldIndexError(c, pos, f)
   831  		return nil
   832  
   833  	default:
   834  		if runMode == finalize && v.status == evaluating {
   835  			err := c.NewPosf(pos, "cycle error referencing %v", f)
   836  			c.AddBottom(&Bottom{
   837  				Code: CycleError,
   838  				Err:  err,
   839  				Node: arc,
   840  			})
   841  			return nil
   842  		}
   843  		arc = &Vertex{Parent: state.node, Label: f, ArcType: ArcPending}
   844  		v.Arcs = append(v.Arcs, arc)
   845  		arcState = arc.getState(c) // TODO: consider using getBareState.
   846  	}
   847  
   848  	if arcState != nil && (!arcState.meets(needTasksDone) || !arcState.meets(arcTypeKnown)) {
   849  		arcState.completePending(attemptOnly)
   850  
   851  		arcState.completeNodeTasks(yield)
   852  
   853  		needs |= arcTypeKnown
   854  
   855  		switch runMode {
   856  		case ignore, attemptOnly:
   857  			// TODO(cycle): ideally, we should be able to require that the
   858  			// arcType be known at this point, but that does not seem to work.
   859  			// Revisit once we have the structural cycle detection in place.
   860  
   861  			// TODO: should we avoid notifying ArcPending vertices here?
   862  			if task != nil {
   863  				arcState.addNotify2(task.node.node, task.id)
   864  			}
   865  			if arc.ArcType == ArcPending {
   866  				return arcReturn
   867  			}
   868  
   869  		case yield:
   870  			arcState.process(needs, yield)
   871  			// continue processing, as successful processing may still result
   872  			// in an invalid field.
   873  
   874  		case finalize:
   875  			// TODO: we should try to always use finalize? Using it results in
   876  			// errors. For now we only use it for let values. Let values are
   877  			// not normally finalized (they may be cached) and as such might
   878  			// not trigger the usual unblocking. Force unblocking may cause
   879  			// some values to be remain unevaluated.
   880  			switch {
   881  			case needs == arcTypeKnown|fieldSetKnown:
   882  				arc.unify(c, needs, finalize, false)
   883  			default:
   884  				// Now we can't finalize, at least try to get as far as we
   885  				// can and only yield if we really have to.
   886  				if !arc.unify(c, needs, attemptOnly, false) {
   887  					arcState.process(needs, yield)
   888  				}
   889  			}
   890  			if arc.ArcType == ArcPending {
   891  				arc.ArcType = ArcNotPresent
   892  			}
   893  		}
   894  	}
   895  
   896  	switch arc.ArcType {
   897  	case ArcMember, ArcRequired:
   898  		return arcReturn
   899  
   900  	case ArcOptional:
   901  		// Technically, this failure also applies to required fields. We assume
   902  		// however, that if a reference field that is made regular will already
   903  		// result in an error, so that piling up another error is not strictly
   904  		// necessary. Note that the spec allows for eliding an error if it is
   905  		// guaranteed another error is generated elsewhere. This does not
   906  		// properly cover the case where a reference is made directly within the
   907  		// definition, but this is fine for the purpose it serves.
   908  		// TODO(refRequired): revisit whether referencing required fields should
   909  		// fail.
   910  		label := f.SelectorString(c.Runtime)
   911  		b := &Bottom{
   912  			Code: IncompleteError,
   913  			Node: v,
   914  			Err: c.NewPosf(pos,
   915  				"cannot reference optional field: %s", label),
   916  		}
   917  		c.AddBottom(b)
   918  		// TODO: yield failure
   919  		return nil
   920  
   921  	case ArcNotPresent:
   922  		v.reportFieldIndexError(c, pos, f)
   923  		return nil
   924  
   925  	case ArcPending:
   926  		// should not happen.
   927  		panic("unreachable")
   928  	}
   929  
   930  	v.reportFieldIndexError(c, pos, f)
   931  	return nil
   932  }
   933  
   934  // accept reports whether the given feature is allowed by the pattern
   935  // constraints.
   936  func (v *Vertex) accept(ctx *OpContext, f Feature) bool {
   937  	// TODO: this is already handled by callers at the moment, but it may be
   938  	// better design to move this here.
   939  	// if v.LookupRaw(f) != nil {
   940  	// 	return true, true
   941  	// }
   942  
   943  	v = v.DerefValue()
   944  
   945  	pc := v.PatternConstraints
   946  	if pc == nil {
   947  		return false
   948  	}
   949  
   950  	// TODO: parhaps use matchPattern again if we have an allowed.
   951  	if matchPattern(ctx, pc.Allowed, f) {
   952  		return true
   953  	}
   954  
   955  	// TODO: fall back for now to just matching any pattern.
   956  	for _, c := range pc.Pairs {
   957  		if matchPattern(ctx, c.Pattern, f) {
   958  			return true
   959  		}
   960  	}
   961  
   962  	return false
   963  }