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 }