cuelang.org/go@v0.10.1/internal/core/adt/eval.go (about) 1 // Copyright 2021 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 eval contains the high level CUE evaluation strategy. 16 // 17 // CUE allows for a significant amount of freedom in order of evaluation due to 18 // the commutativity of the unification operation. This package implements one 19 // of the possible strategies. 20 package adt 21 22 // TODO: 23 // - result should be nodeContext: this allows optionals info to be extracted 24 // and computed. 25 // 26 27 import ( 28 "fmt" 29 30 "cuelang.org/go/cue/ast" 31 "cuelang.org/go/cue/errors" 32 "cuelang.org/go/cue/stats" 33 "cuelang.org/go/cue/token" 34 ) 35 36 // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 37 // 38 // - Reuse work from previous cycles. For instance, if we can guarantee that a 39 // value is always correct for partial results, we can just process the arcs 40 // going from Partial to Finalized, without having to reevaluate the value. 41 // 42 // - Test closedness far more thoroughly. 43 // 44 45 func (c *OpContext) Stats() *stats.Counts { 46 return &c.stats 47 } 48 49 // TODO: Note: NewContext takes essentially a cue.Value. By making this 50 // type more central, we can perhaps avoid context creation. 51 52 // func NewContext(r Runtime, v *Vertex) *OpContext { 53 // e := NewUnifier(r) 54 // return e.NewContext(v) 55 // } 56 57 var structSentinel = &StructMarker{} 58 59 var incompleteSentinel = &Bottom{ 60 Code: IncompleteError, 61 Err: errors.Newf(token.NoPos, "incomplete"), 62 } 63 64 // evaluate returns the evaluated value associated with v. It may return a 65 // partial result. That is, if v was not yet unified, it may return a 66 // concrete value that must be the result assuming the configuration has no 67 // errors. 68 // 69 // This semantics allows CUE to break reference cycles in a straightforward 70 // manner. 71 // 72 // Vertex v must still be evaluated at some point to catch the underlying 73 // error. 74 // 75 // TODO: return *Vertex 76 func (c *OpContext) evaluate(v *Vertex, r Resolver, state combinedFlags) Value { 77 if v.isUndefined() { 78 // Use node itself to allow for cycle detection. 79 c.unify(v, state) 80 81 if v.ArcType == ArcPending { 82 if v.status == evaluating { 83 for ; v.Parent != nil && v.ArcType == ArcPending; v = v.Parent { 84 } 85 err := c.Newf("cycle with field %v", r) 86 b := &Bottom{Code: CycleError, Err: err} 87 v.setValue(c, v.status, b) 88 return b 89 // TODO: use this instead, as is usual for incomplete errors, 90 // and also move this block one scope up to also apply to 91 // defined arcs. In both cases, though, doing so results in 92 // some errors to be misclassified as evaluation error. 93 // c.AddBottom(b) 94 // return nil 95 } 96 c.undefinedFieldError(v, IncompleteError) 97 return nil 98 } 99 } 100 101 if n := v.state; n != nil { 102 n.assertInitialized() 103 104 if n.errs != nil && !n.errs.IsIncomplete() { 105 return n.errs 106 } 107 if n.scalar != nil && isCyclePlaceholder(v.BaseValue) { 108 return n.scalar 109 } 110 } 111 112 switch x := v.BaseValue.(type) { 113 case *Bottom: 114 if x.IsIncomplete() { 115 c.AddBottom(x) 116 return nil 117 } 118 return x 119 120 case nil: 121 if v.state != nil { 122 switch x := v.state.getValidators(finalized).(type) { 123 case Value: 124 return x 125 default: 126 w := *v 127 w.BaseValue = x 128 return &w 129 } 130 } 131 // This may happen if the evaluator is invoked outside of regular 132 // evaluation, such as in dependency analysis. 133 return nil 134 } 135 136 if v.status < finalized && v.state != nil && !c.isDevVersion() { 137 // TODO: errors are slightly better if we always add addNotify, but 138 // in this case it is less likely to cause a performance penalty. 139 // See https://cuelang.org/issue/661. It may be possible to 140 // relax this again once we have proper tests to prevent regressions of 141 // that issue. 142 if !v.state.done() || v.state.errs != nil { 143 v.state.addNotify(c.vertex, nil) 144 } 145 } 146 147 return v 148 } 149 150 // unify unifies values of a Vertex to and stores the result in the Vertex. If 151 // unify was called on v before it returns the cached results. 152 // state can be used to indicate to which extent processing should continue. 153 // state == finalized means it is evaluated to completion. See vertexStatus 154 // for more details. 155 func (c *OpContext) unify(v *Vertex, flags combinedFlags) { 156 if c.isDevVersion() { 157 requires, mode := flags.conditions(), flags.runMode() 158 v.unify(c, requires, mode) 159 return 160 } 161 162 // defer c.PopVertex(c.PushVertex(v)) 163 if c.LogEval > 0 { 164 c.nest++ 165 c.Logf(v, "Unify") 166 defer func() { 167 c.Logf(v, "END Unify") 168 c.nest-- 169 }() 170 } 171 172 // Ensure a node will always have a nodeContext after calling Unify if it is 173 // not yet Finalized. 174 n := v.getNodeContext(c, 1) 175 defer v.freeNode(n) 176 177 state := flags.vertexStatus() 178 179 // TODO(cycle): verify this happens in all cases when we need it. 180 if n != nil && v.Parent != nil && v.Parent.state != nil { 181 n.depth = v.Parent.state.depth + 1 182 } 183 184 if state <= v.Status() && 185 state == partial && 186 v.isDefined() && 187 n != nil && n.scalar != nil { 188 return 189 } 190 191 switch v.Status() { 192 case evaluating: 193 n.insertConjuncts(state) 194 return 195 196 case evaluatingArcs: 197 Assertf(c, v.status > unprocessed, "unexpected status %d", v.status) 198 return 199 200 case 0: 201 if v.Label.IsDef() { 202 v.Closed = true 203 } 204 205 if v.Parent != nil { 206 if v.Parent.Closed { 207 v.Closed = true 208 } 209 } 210 211 defer c.PopArc(c.PushArc(v)) 212 213 v.updateStatus(evaluating) 214 215 if p := v.Parent; p != nil && p.state != nil && v.Label.IsString() { 216 for _, s := range p.state.node.Structs { 217 if s.Disable { 218 continue 219 } 220 s.MatchAndInsert(n.ctx, v) 221 } 222 } 223 224 c.stats.Unifications++ 225 226 // Set the cache to a cycle error to ensure a cyclic reference will result 227 // in an error if applicable. A cyclic error may be ignored for 228 // non-expression references. The cycle error may also be removed as soon 229 // as there is evidence what a correct value must be, but before all 230 // validation has taken place. 231 // 232 // TODO(cycle): having a more recursive algorithm would make this 233 // special cycle handling unnecessary. 234 v.BaseValue = cycle 235 236 if c.HasErr() { 237 n.addBottom(c.errs) 238 } 239 240 // NOTE: safeguard against accidentally entering the 'unprocessed' state 241 // twice. 242 n.conjuncts = n.conjuncts[:0] 243 244 for i, c := range v.Conjuncts { 245 n.addConjunction(c, i) 246 } 247 if n.insertConjuncts(state) { 248 n.maybeSetCache() 249 v.updateStatus(partial) 250 return 251 } 252 253 fallthrough 254 255 case partial, conjuncts: 256 // TODO: remove this optimization or make it correct. 257 // No need to do further processing when we have errors and all values 258 // have been considered. 259 // TODO: is checkClosed really still necessary here? 260 if v.status == conjuncts && (n.hasErr() || !n.checkClosed(state)) { 261 if err := n.getErr(); err != nil { 262 b, _ := v.BaseValue.(*Bottom) 263 v.BaseValue = CombineErrors(nil, b, err) 264 } 265 break 266 } 267 268 defer c.PopArc(c.PushArc(v)) 269 270 n.insertConjuncts(state) 271 272 v.status = evaluating 273 274 // Use maybeSetCache for cycle breaking 275 for n.maybeSetCache(); n.expandOne(partial); n.maybeSetCache() { 276 } 277 278 n.doNotify() 279 280 if !n.done() { 281 switch { 282 case state < conjuncts: 283 n.node.updateStatus(partial) 284 return 285 286 case state == conjuncts: 287 if err := n.incompleteErrors(true); err != nil && err.Code < CycleError { 288 n.node.AddErr(c, err) 289 } else { 290 n.node.updateStatus(partial) 291 } 292 return 293 } 294 } 295 296 // Disjunctions should always be finalized. If there are nested 297 // disjunctions the last one should be finalized. 298 disState := state 299 if len(n.disjunctions) > 0 && disState != finalized { 300 disState = finalized 301 } 302 n.expandDisjuncts(disState, n, maybeDefault, false, true) 303 304 n.finalizeDisjuncts() 305 306 switch len(n.disjuncts) { 307 case 0: 308 case 1: 309 x := n.disjuncts[0].result 310 x.state = nil 311 x.cyclicReferences = n.node.cyclicReferences 312 *v = x 313 314 default: 315 d := n.createDisjunct() 316 v.BaseValue = d 317 // The conjuncts will have too much information. Better have no 318 // information than incorrect information. 319 for _, d := range d.Values { 320 d, ok := d.(*Vertex) 321 if !ok { 322 continue 323 } 324 // We clear the conjuncts for now. As these disjuncts are for API 325 // use only, we will fill them out when necessary (using Defaults). 326 d.Conjuncts = nil 327 328 // TODO: use a more principled form of dereferencing. For instance, 329 // disjuncts could already be assumed to be the given Vertex, and 330 // the main vertex could be dereferenced during evaluation. 331 for _, a := range d.Arcs { 332 for _, x := range a.Conjuncts { 333 // All the environments for embedded structs need to be 334 // dereferenced. 335 for env := x.Env; env != nil && env.Vertex == v; env = env.Up { 336 env.Vertex = d 337 } 338 } 339 } 340 } 341 v.Arcs = nil 342 v.ChildErrors = nil 343 // v.Structs = nil // TODO: should we keep or discard the Structs? 344 // TODO: how to represent closedness information? Do we need it? 345 } 346 347 // If the state has changed, it is because a disjunct has been run, or 348 // because a single disjunct has replaced it. Restore the old state as 349 // to not confuse memory management. 350 v.state = n 351 352 // We don't do this in postDisjuncts, as it should only be done after 353 // completing all disjunctions. 354 if !n.done() { 355 if err := n.incompleteErrors(true); err != nil { 356 b := n.node.Bottom() 357 if b != err { 358 err = CombineErrors(n.ctx.src, b, err) 359 } 360 n.node.BaseValue = err 361 } 362 } 363 364 assertStructuralCycle(n) 365 366 if state != finalized { 367 return 368 } 369 370 if v.BaseValue == nil { 371 v.BaseValue = n.getValidators(finalized) 372 } 373 374 // Free memory here? 375 v.updateStatus(finalized) 376 377 case finalized: 378 } 379 } 380 381 // insertConjuncts inserts conjuncts previously not inserted. 382 func (n *nodeContext) insertConjuncts(state vertexStatus) bool { 383 unreachableForDev(n.ctx) 384 385 // Exit early if we have a concrete value and only need partial results. 386 if state == partial { 387 for n.conjunctsPartialPos < len(n.conjuncts) { 388 c := &n.conjuncts[n.conjunctsPartialPos] 389 n.conjunctsPartialPos++ 390 if c.done { 391 continue 392 } 393 if v, ok := c.C.Elem().(Value); ok && IsConcrete(v) { 394 c.done = true 395 n.addValueConjunct(c.C.Env, v, c.C.CloseInfo) 396 } 397 } 398 if n.scalar != nil && n.node.isDefined() { 399 return true 400 } 401 } 402 for n.conjunctsPos < len(n.conjuncts) { 403 nInfos := len(n.node.Structs) 404 p := &n.conjuncts[n.conjunctsPos] 405 n.conjunctsPos++ 406 if p.done { 407 continue 408 } 409 410 // Initially request a Partial state to allow cyclic references to 411 // resolve more naturally first. This results in better error messages 412 // and less operations. 413 n.addExprConjunct(p.C, partial) 414 p.done = true 415 416 // Record the OptionalTypes for all structs that were inferred by this 417 // Conjunct. This information can be used by algorithms such as trim. 418 for i := nInfos; i < len(n.node.Structs); i++ { 419 n.node.Conjuncts[p.index].CloseInfo.FieldTypes |= n.node.Structs[i].types 420 } 421 } 422 return false 423 } 424 425 // finalizeDisjuncts: incomplete errors are kept around and not removed early. 426 // This call filters the incomplete errors and removes them 427 // 428 // This also collects all errors of empty disjunctions. These cannot be 429 // collected during the finalization state of individual disjuncts. Care should 430 // be taken to only call this after all disjuncts have been finalized. 431 func (n *nodeContext) finalizeDisjuncts() { 432 a := n.disjuncts 433 if len(a) == 0 { 434 return 435 } 436 k := 0 437 for i, d := range a { 438 switch d.finalDone() { 439 case true: 440 a[k], a[i] = d, a[k] 441 k++ 442 default: 443 if err := d.incompleteErrors(true); err != nil { 444 n.disjunctErrs = append(n.disjunctErrs, err) 445 } 446 } 447 d.free() 448 } 449 if k == 0 { 450 n.makeError() 451 } 452 n.disjuncts = a[:k] 453 } 454 455 func (n *nodeContext) doNotify() { 456 if n.errs == nil || len(n.notify) == 0 { 457 return 458 } 459 for _, rec := range n.notify { 460 v := rec.v 461 if v.state == nil { 462 if b := v.Bottom(); b != nil { 463 v.BaseValue = CombineErrors(nil, b, n.errs) 464 } else { 465 v.BaseValue = n.errs 466 } 467 } else { 468 v.state.addBottom(n.errs) 469 } 470 } 471 n.notify = n.notify[:0] 472 } 473 474 func (n *nodeContext) postDisjunct(state vertexStatus) { 475 ctx := n.ctx 476 unreachableForDev(ctx) 477 478 for { 479 // Use maybeSetCache for cycle breaking 480 for n.maybeSetCache(); n.expandOne(state); n.maybeSetCache() { 481 } 482 483 if !n.addLists(oldOnly(state)) { 484 break 485 } 486 } 487 488 if n.aStruct != nil { 489 n.updateNodeType(StructKind, n.aStruct, n.aStructID) 490 } 491 492 if len(n.selfComprehensions) > 0 { 493 // Up to here all comprehensions with sources other than this node will 494 // have had a chance to run. We can now run self-referencing 495 // comprehensions with the restriction that they cannot add new arcs. 496 // 497 // Note: we should only set this in case of self-referential 498 // comprehensions. A comprehension in a parent node may still add 499 // arcs to this node, even if it has reached AllConjunctsDone status, 500 // as long as any evaluation did not rely on its specific set of arcs. 501 // Example: 502 // 503 // a: { 504 // b: _env: c: 1 505 // 506 // // Using dynamic field ("b") prevents the evaluation of the 507 // // comprehension to be pushed down to env: and instead evaluates 508 // // it before b is completed. Even though b needs to reach state 509 // // AllConjunctsDone before evaluating b._env, it is still okay 510 // // to add arcs to b after this evaluation: only the set of arcs 511 // // in b._env needs to be frozen after that. 512 // for k2, v2 in b._env { 513 // ("b"): env: (k2): v2 514 // } 515 // } 516 n.node.LockArcs = true 517 518 n.injectSelfComprehensions(state) 519 } 520 521 for n.expandOne(state) { 522 } 523 524 switch err := n.getErr(); { 525 case err != nil: 526 if err.Code < IncompleteError && n.node.ArcType == ArcPending { 527 n.node.ArcType = ArcMember 528 } 529 n.node.BaseValue = err 530 n.errs = nil 531 532 default: 533 if isCyclePlaceholder(n.node.BaseValue) { 534 if !n.done() { 535 n.node.BaseValue = n.incompleteErrors(true) 536 } else { 537 n.node.BaseValue = nil 538 } 539 } 540 // TODO: this ideally should be done here. However, doing so causes 541 // a somewhat more aggressive cutoff in disjunction cycles, which cause 542 // some incompatibilities. Fix in another CL. 543 // 544 // else if !n.done() { 545 // n.expandOne() 546 // if err := n.incompleteErrors(); err != nil { 547 // n.node.BaseValue = err 548 // } 549 // } 550 551 // We are no longer evaluating. 552 553 n.validateValue(state) 554 555 v := n.node.Value() 556 557 // TODO(perf): only delay processing of actual non-monotonic checks. 558 skip := n.skipNonMonotonicChecks() 559 if v != nil && IsConcrete(v) && !skip { 560 for _, v := range n.checks { 561 // TODO(errors): make Validate return bottom and generate 562 // optimized conflict message. Also track and inject IDs 563 // to determine origin location.s 564 if b := ctx.Validate(v, n.node); b != nil { 565 n.addBottom(b) 566 } 567 } 568 } 569 570 if v == nil { 571 break 572 } 573 574 switch { 575 case v.Kind() == ListKind: 576 for _, a := range n.node.Arcs { 577 if a.Label.Typ() == StringLabel && a.IsDefined(ctx) { 578 n.addErr(ctx.Newf("list may not have regular fields")) 579 // TODO(errors): add positions for list and arc definitions. 580 581 } 582 } 583 584 // case !isStruct(n.node) && v.Kind() != BottomKind: 585 // for _, a := range n.node.Arcs { 586 // if a.Label.IsRegular() { 587 // n.addErr(errors.Newf(token.NoPos, 588 // // TODO(errors): add positions of non-struct values and arcs. 589 // "cannot combine scalar values with arcs")) 590 // } 591 // } 592 } 593 } 594 595 n.completeArcs(state) 596 } 597 598 // validateValue checks collected bound validators and checks them against 599 // the current value. If there is no value, it sets the current value 600 // to these validators itself. 601 // 602 // Before it does this, it also checks whether n is of another incompatible 603 // type, like struct. This prevents validators from being inadvertently set. 604 // TODO: optimize this function for new implementation. 605 func (n *nodeContext) validateValue(state vertexStatus) { 606 ctx := n.ctx 607 608 // Either set to Conjunction or error. 609 // TODO: verify and simplify the below code to determine whether 610 // something is a struct. 611 markStruct := false 612 if n.aStruct != nil { 613 markStruct = true 614 } else if len(n.node.Structs) > 0 { 615 markStruct = n.kind&StructKind != 0 && !n.hasTop 616 } 617 v := n.node.DerefValue().Value() 618 if n.node.BaseValue == nil && markStruct { 619 n.node.BaseValue = &StructMarker{} 620 v = n.node 621 } 622 if v != nil && IsConcrete(v) { 623 // Also check when we already have errors as we may find more 624 // serious errors and would like to know about all errors anyway. 625 626 if n.lowerBound != nil { 627 if b := ctx.Validate(n.lowerBound, v); b != nil { 628 // TODO(errors): make Validate return boolean and generate 629 // optimized conflict message. Also track and inject IDs 630 // to determine origin location.s 631 if e, _ := b.Err.(*ValueError); e != nil { 632 e.AddPosition(n.lowerBound) 633 e.AddPosition(v) 634 } 635 n.addBottom(b) 636 } 637 } 638 if n.upperBound != nil { 639 if b := ctx.Validate(n.upperBound, v); b != nil { 640 // TODO(errors): make Validate return boolean and generate 641 // optimized conflict message. Also track and inject IDs 642 // to determine origin location.s 643 if e, _ := b.Err.(*ValueError); e != nil { 644 e.AddPosition(n.upperBound) 645 e.AddPosition(v) 646 } 647 n.addBottom(b) 648 } 649 } 650 651 } else if state == finalized { 652 n.node.BaseValue = n.getValidators(finalized) 653 } 654 } 655 656 // incompleteErrors reports all errors from uncompleted conjuncts. 657 // If final is true, errors are permanent and reported to parents. 658 func (n *nodeContext) incompleteErrors(final bool) *Bottom { 659 // collect incomplete errors. 660 var err *Bottom // n.incomplete 661 for _, d := range n.dynamicFields { 662 err = CombineErrors(nil, err, d.err) 663 } 664 for _, c := range n.comprehensions { 665 if c.err == nil { 666 continue 667 } 668 err = CombineErrors(nil, err, c.err) 669 670 // TODO: use this code once possible. 671 // 672 // Add comprehension to ensure incomplete error is inserted. This 673 // ensures that the error is reported in the Vertex where the 674 // comprehension was defined, and not just in the node below. This, in 675 // turn, is necessary to support certain logic, like export, that 676 // expects to be able to detect an "incomplete" error at the first level 677 // where it is necessary. 678 // if c.node.status != Finalized { 679 // n := c.node.getNodeContext(n.ctx) 680 // n.comprehensions = append(n.comprehensions, c) 681 // } else { 682 // n.node.AddErr(n.ctx, err) 683 // } 684 // n := d.node.getNodeContext(ctx) 685 // n.addBottom(err) 686 if final && c.vertex != nil && c.vertex.status != finalized { 687 c.vertex.state.assertInitialized() 688 c.vertex.state.addBottom(err) 689 c.vertex = nil 690 } 691 } 692 for _, c := range n.selfComprehensions { 693 if c.err == nil { 694 continue 695 } 696 697 err = CombineErrors(nil, err, c.err) 698 699 // TODO: use this code once possible. 700 // 701 // Add comprehension to ensure incomplete error is inserted. This 702 // ensures that the error is reported in the Vertex where the 703 // comprehension was defined, and not just in the node below. This, in 704 // turn, is necessary to support certain logic, like export, that 705 // expects to be able to detect an "incomplete" error at the first level 706 // where it is necessary. 707 // if c.node.status != Finalized { 708 // n := c.node.getNodeContext(n.ctx) 709 // n.comprehensions = append(n.comprehensions, c) 710 // } else { 711 // n.node.AddErr(n.ctx, err) 712 // } 713 // n := d.node.getNodeContext(ctx) 714 // n.addBottom(err) 715 if c.vertex != nil && c.vertex.status != finalized { 716 c.vertex.state.addBottom(err) 717 c.vertex = nil 718 } 719 } 720 for _, x := range n.exprs { 721 err = CombineErrors(nil, err, x.err) 722 } 723 if err == nil { 724 // safeguard. 725 err = incompleteSentinel 726 } 727 if err.Code < IncompleteError { 728 n.node.ArcType = ArcMember 729 } 730 return err 731 } 732 733 // TODO(perf): ideally we should always perform a closedness check if 734 // state is Finalized. This is currently not possible when computing a 735 // partial disjunction as the closedness information is not yet 736 // complete, possibly leading to a disjunct to be rejected prematurely. 737 // It is probably possible to fix this if we could add StructInfo 738 // structures demarked per conjunct. 739 // 740 // In practice this should not be a problem: when disjuncts originate 741 // from the same disjunct, they will have the same StructInfos, and thus 742 // Equal is able to equate them even in the presence of optional field. 743 // In general, combining any limited set of disjuncts will soon reach 744 // a fixed point where duplicate elements can be eliminated this way. 745 // 746 // Note that not checking closedness is irrelevant for disjunctions of 747 // scalars. This means it also doesn't hurt performance where structs 748 // have a discriminator field (e.g. Kubernetes). We should take care, 749 // though, that any potential performance issues are eliminated for 750 // Protobuf-like oneOf fields. 751 func (n *nodeContext) checkClosed(state vertexStatus) bool { 752 unreachableForDev(n.ctx) 753 754 ignore := state != finalized || n.skipNonMonotonicChecks() 755 756 v := n.node 757 if !v.Label.IsInt() && v.Parent != nil && !ignore && v.ArcType <= ArcRequired { 758 ctx := n.ctx 759 // Visit arcs recursively to validate and compute error. 760 if _, err := verifyArc2(ctx, v.Label, v, v.Closed); err != nil { 761 // Record error in child node to allow recording multiple 762 // conflicts at the appropriate place, to allow valid fields to 763 // be represented normally and, most importantly, to avoid 764 // recursive processing of a disallowed field. 765 v.SetValue(ctx, err) 766 return false 767 } 768 } 769 return true 770 } 771 772 func (n *nodeContext) completeArcs(state vertexStatus) { 773 unreachableForDev(n.ctx) 774 775 if DebugSort > 0 { 776 DebugSortArcs(n.ctx, n.node) 777 } 778 779 if n.node.hasAllConjuncts || n.node.Parent == nil { 780 n.node.setParentDone() 781 } 782 783 // At this point, if this arc is of type arcVoid, it means that the value 784 // may still be modified by child arcs. So in this case we must now process 785 // all arcs to be sure we get the correct result. 786 // For other cases we terminate early as this results in considerably 787 // better error messages. 788 if state <= conjuncts && 789 // Is allowed to go one step back. See Vertex.UpdateStatus. 790 n.node.status <= state+1 && 791 (!n.node.hasPendingArc || n.node.ArcType == ArcMember) { 792 793 n.node.updateStatus(conjuncts) 794 return 795 } 796 797 n.node.updateStatus(evaluatingArcs) 798 799 ctx := n.ctx 800 801 if !assertStructuralCycle(n) { 802 k := 0 803 // Visit arcs recursively to validate and compute error. 804 for _, a := range n.node.Arcs { 805 // Call UpdateStatus here to be absolutely sure the status is set 806 // correctly and that we are not regressing. 807 n.node.updateStatus(evaluatingArcs) 808 809 wasVoid := a.ArcType == ArcPending 810 811 ctx.unify(a, oldOnly(finalized)) 812 813 if a.ArcType == ArcPending { 814 continue 815 } 816 817 // Errors are allowed in let fields. Handle errors and failure to 818 // complete accordingly. 819 if !a.Label.IsLet() && a.ArcType <= ArcRequired { 820 // Don't set the state to Finalized if the child arcs are not done. 821 if state == finalized && a.status < finalized { 822 state = conjuncts 823 } 824 825 if err := a.Bottom(); err != nil { 826 n.node.AddChildError(err) 827 } 828 } 829 830 n.node.Arcs[k] = a 831 k++ 832 833 switch { 834 case a.ArcType > ArcRequired, !a.Label.IsString(): 835 case n.kind&StructKind == 0: 836 if !n.node.IsErr() { 837 n.reportFieldMismatch(pos(a.Value()), nil, a.Label, n.node.Value()) 838 } 839 case !wasVoid: 840 case n.kind == TopKind: 841 // Theoretically it may be possible that a "void" arc references 842 // this top value where it really should have been a struct. One 843 // way to solve this is to have two passes over the arcs, where 844 // the first pass additionally analyzes whether comprehensions 845 // will yield values and "un-voids" an arc ahead of the rest. 846 // 847 // At this moment, though, I fail to see a possibility to create 848 // faulty CUE using this mechanism, though. At most error 849 // messages are a bit unintuitive. This may change once we have 850 // functionality to reflect on types. 851 if !n.node.IsErr() { 852 n.node.BaseValue = &StructMarker{} 853 n.kind = StructKind 854 } 855 } 856 } 857 n.node.Arcs = n.node.Arcs[:k] 858 859 for _, c := range n.postChecks { 860 f := ctx.PushState(c.env, c.expr.Source()) 861 862 // TODO(errors): make Validate return bottom and generate 863 // optimized conflict message. Also track and inject IDs 864 // to determine origin location.s 865 v := ctx.evalState(c.expr, oldOnly(finalized)) 866 v, _ = ctx.getDefault(v) 867 v = Unwrap(v) 868 869 switch _, isError := v.(*Bottom); { 870 case isError == c.expectError: 871 default: 872 n.node.AddErr(ctx, &Bottom{ 873 Src: c.expr.Source(), 874 Code: CycleError, 875 Err: ctx.NewPosf(pos(c.expr), 876 "circular dependency in evaluation of conditionals: %v changed after evaluation", 877 ctx.Str(c.expr)), 878 }) 879 } 880 881 ctx.PopState(f) 882 } 883 } 884 885 if err := n.getErr(); err != nil { 886 n.errs = nil 887 if b, _ := n.node.BaseValue.(*Bottom); b != nil { 888 err = CombineErrors(nil, b, err) 889 } 890 n.node.BaseValue = err 891 } 892 893 b, hasErr := n.node.BaseValue.(*Bottom) 894 if !hasErr && b != cycle { 895 n.checkClosed(state) 896 } 897 898 // Strip struct literals that were not initialized and are not part 899 // of the output. 900 // 901 // TODO(perf): we could keep track if any such structs exist and only 902 // do this removal if there is a change of shrinking the list. 903 k := 0 904 for _, s := range n.node.Structs { 905 if s.initialized { 906 n.node.Structs[k] = s 907 k++ 908 } 909 } 910 n.node.Structs = n.node.Structs[:k] 911 912 n.node.updateStatus(finalized) 913 } 914 915 // TODO: this is now a sentinel. Use a user-facing error that traces where 916 // the cycle originates. 917 var cycle = &Bottom{ 918 Err: errors.Newf(token.NoPos, "cycle error"), 919 Code: CycleError, 920 } 921 922 func isCyclePlaceholder(v BaseValue) bool { 923 // TODO: do not mark cycle in BaseValue. 924 if a, _ := v.(*Vertex); a != nil { 925 v = a.DerefValue().BaseValue 926 } 927 return v == cycle 928 } 929 930 func (n *nodeContext) createDisjunct() *Disjunction { 931 a := make([]Value, len(n.disjuncts)) 932 p := 0 933 hasDefaults := false 934 for i, x := range n.disjuncts { 935 v := new(Vertex) 936 *v = x.result 937 v.state = nil 938 switch x.defaultMode { 939 case isDefault: 940 a[i] = a[p] 941 a[p] = v 942 p++ 943 hasDefaults = true 944 945 case notDefault: 946 hasDefaults = true 947 fallthrough 948 case maybeDefault: 949 a[i] = v 950 } 951 } 952 // TODO: disambiguate based on concrete values. 953 // TODO: consider not storing defaults. 954 // if p > 0 { 955 // a = a[:p] 956 // } 957 return &Disjunction{ 958 Values: a, 959 NumDefaults: p, 960 HasDefaults: hasDefaults, 961 } 962 } 963 964 type arcKey struct { 965 arc *Vertex 966 id CloseInfo 967 } 968 969 // A nodeContext is used to collate all conjuncts of a value to facilitate 970 // unification. Conceptually order of unification does not matter. However, 971 // order has relevance when performing checks of non-monotic properties. Such 972 // checks should only be performed once the full value is known. 973 type nodeContext struct { 974 nextFree *nodeContext 975 refCount int 976 977 // Keep node out of the nodeContextState to make them more accessible 978 // for source-level debuggers. 979 node *Vertex 980 981 // underlying is the original Vertex that this node overlays. It should be 982 // set for all Vertex values that were cloned. 983 underlying *Vertex 984 985 // overlays is set if this node is the root of a disjunct created in 986 // doDisjunct. It points to the direct parent nodeContext. 987 overlays *nodeContext 988 989 nodeContextState 990 991 scheduler 992 993 // Below are slices that need to be managed when cloning and reclaiming 994 // nodeContexts for reuse. We want to ensure that, instead of setting 995 // slices to nil, we truncate the existing buffers so that they do not 996 // need to be reallocated upon reuse of the nodeContext. 997 998 arcMap []arcKey // not copied for cloning 999 1000 // notify is used to communicate errors in cyclic dependencies. 1001 // TODO: also use this to communicate increasingly more concrete values. 1002 notify []receiver 1003 1004 // Conjuncts holds a reference to the Vertex Arcs that still need 1005 // processing. It does NOT need to be copied. 1006 conjuncts []conjunct 1007 cyclicConjuncts []cyclicConjunct 1008 1009 dynamicFields []envDynamic 1010 comprehensions []envYield 1011 selfComprehensions []envYield // comprehensions iterating over own struct. 1012 1013 // Expression conjuncts 1014 lists []envList 1015 vLists []*Vertex 1016 exprs []envExpr 1017 1018 checks []Validator // BuiltinValidator, other bound values. 1019 postChecks []envCheck // Check non-monotonic constraints, among other things. 1020 1021 // Disjunction handling 1022 disjunctions []envDisjunct 1023 1024 // disjunctCCs holds the close context that represent "holes" in which 1025 // pending disjuncts are to be inserted for the clone represented by this 1026 // nodeContext. Holes that are not yet filled will always need to be cloned 1027 // when a disjunction branches in doDisjunct. 1028 // 1029 // Holes may accumulate as nested disjunctions get added and filled holes 1030 // may be removed. So the list of disjunctCCs may differ from the number 1031 // of disjunctions. 1032 disjunctCCs []disjunctHole 1033 1034 // usedDefault indicates the for each of possibly multiple parent 1035 // disjunctions whether it is unified with a default disjunct or not. 1036 // This is then later used to determine whether a disjunction should 1037 // be treated as a marked disjunction. 1038 usedDefault []defaultInfo 1039 1040 // disjuncts holds disjuncts that evaluated to a non-bottom value. 1041 // TODO: come up with a better name. 1042 disjuncts []*nodeContext 1043 buffer []*nodeContext 1044 disjunctErrs []*Bottom 1045 disjunct Conjunct 1046 1047 // snapshot holds the last value of the vertex before calling postDisjunct. 1048 snapshot Vertex 1049 1050 // Result holds the last evaluated value of the vertex after calling 1051 // postDisjunct. 1052 result Vertex 1053 } 1054 1055 type conjunct struct { 1056 C Conjunct 1057 1058 // done marks that this conjunct has been inserted. This prevents a 1059 // conjunct from being processed more than once, for instance, when 1060 // insertConjuncts is called more than once for the same node. 1061 done bool 1062 index int // index of the original conjunct in Vertex.Conjuncts 1063 } 1064 1065 type nodeContextState struct { 1066 // isInitialized indicates whether conjuncts have been inserted in the node. 1067 // Use node.isInitialized() to more generally check whether conjuncts have 1068 // been processed. 1069 isInitialized bool 1070 1071 // toComplete marks whether completeNodeTasks needs to be called on this 1072 // node after a corresponding task has been completed. 1073 toComplete bool 1074 1075 // isCompleting > 0 indicates whether a call to completeNodeTasks is in 1076 // progress. 1077 isCompleting int 1078 1079 // evalDept is a number that is assigned when evaluating arcs and is set to 1080 // detect structural cycles. This value may be temporarily altered when a 1081 // node descends into evaluating a value that may be an error (pattern 1082 // constraints, optional fields, etc.). A non-zero value always indicates 1083 // that there are cyclic references, though. 1084 evalDepth int 1085 1086 // State info 1087 1088 hasTop bool 1089 hasCycle bool // has conjunct with structural cycle 1090 hasNonCycle bool // has conjunct without structural cycle 1091 1092 isShared bool // set if we are currently structure sharing. 1093 noSharing bool // set if structure sharing is not allowed 1094 shared Conjunct // the original conjunct that led to sharing 1095 sharedID CloseInfo // the original CloseInfo that led to sharing 1096 origBaseValue BaseValue // the BaseValue that structure sharing replaces. 1097 1098 depth int32 1099 defaultMode defaultMode 1100 1101 // Value info 1102 1103 kind Kind 1104 kindExpr Expr // expr that adjust last value (for error reporting) 1105 kindID CloseInfo // for error tracing 1106 1107 // Current value (may be under construction) 1108 scalar Value // TODO: use Value in node. 1109 scalarID CloseInfo 1110 1111 aStruct Expr 1112 aStructID CloseInfo 1113 1114 // List fields 1115 listIsClosed bool 1116 maxListLen int 1117 maxNode Expr 1118 1119 lowerBound *BoundValue // > or >= 1120 upperBound *BoundValue // < or <= 1121 errs *Bottom 1122 1123 // Slice positions 1124 1125 // conjunctsPos is an index into conjuncts indicating the next conjunct 1126 // to process. This is used to avoids processing a conjunct twice in some 1127 // cases where there is an evaluation cycle. 1128 conjunctsPos int 1129 // conjunctsPartialPos is like conjunctsPos, but for the 'partial' phase 1130 // of processing where conjuncts are only processed as concrete scalars. 1131 conjunctsPartialPos int 1132 1133 arcPos int 1134 } 1135 1136 // A receiver receives notifications. 1137 type receiver struct { 1138 v *Vertex 1139 cc *closeContext 1140 } 1141 1142 // Logf substitutes args in format. Arguments of type Feature, Value, and Expr 1143 // are printed in human-friendly formats. The printed string is prefixed and 1144 // indented with the path associated with the current nodeContext. 1145 func (n *nodeContext) Logf(format string, args ...interface{}) { 1146 n.ctx.Logf(n.node, format, args...) 1147 } 1148 1149 type defaultInfo struct { 1150 // parentMode indicates whether this values was used as a default value, 1151 // based on the parent mode. 1152 parentMode defaultMode 1153 1154 // The result of default evaluation for a nested disjunction. 1155 nestedMode defaultMode 1156 1157 origMode defaultMode 1158 } 1159 1160 func (n *nodeContext) addNotify(v *Vertex, cc *closeContext) { 1161 unreachableForDev(n.ctx) 1162 1163 if v != nil && !n.node.hasAllConjuncts { 1164 n.notify = append(n.notify, receiver{v, cc}) 1165 } 1166 } 1167 1168 func (n *nodeContext) clone() *nodeContext { 1169 d := n.ctx.newNodeContext(n.node) 1170 1171 d.refCount++ 1172 1173 d.ctx = n.ctx 1174 d.node = n.node 1175 1176 d.nodeContextState = n.nodeContextState 1177 1178 d.arcMap = append(d.arcMap, n.arcMap...) 1179 d.notify = append(d.notify, n.notify...) 1180 1181 n.scheduler.cloneInto(&d.scheduler) 1182 1183 d.conjuncts = append(d.conjuncts, n.conjuncts...) 1184 d.cyclicConjuncts = append(d.cyclicConjuncts, n.cyclicConjuncts...) 1185 d.dynamicFields = append(d.dynamicFields, n.dynamicFields...) 1186 d.comprehensions = append(d.comprehensions, n.comprehensions...) 1187 d.selfComprehensions = append(d.selfComprehensions, n.selfComprehensions...) 1188 d.lists = append(d.lists, n.lists...) 1189 d.vLists = append(d.vLists, n.vLists...) 1190 d.exprs = append(d.exprs, n.exprs...) 1191 d.checks = append(d.checks, n.checks...) 1192 d.postChecks = append(d.postChecks, n.postChecks...) 1193 1194 d.usedDefault = append(d.usedDefault, n.usedDefault...) 1195 1196 // Do not clone other disjunction-related slices, like disjuncts and buffer: 1197 // disjunction slices are managed by disjunction processing directly. 1198 1199 return d 1200 } 1201 1202 func (c *OpContext) newNodeContext(node *Vertex) *nodeContext { 1203 if n := c.freeListNode; n != nil { 1204 c.stats.Reused++ 1205 c.freeListNode = n.nextFree 1206 1207 *n = nodeContext{ 1208 scheduler: scheduler{ctx: c}, 1209 node: node, 1210 nodeContextState: nodeContextState{ 1211 kind: TopKind, 1212 }, 1213 arcMap: n.arcMap[:0], 1214 conjuncts: n.conjuncts[:0], 1215 cyclicConjuncts: n.cyclicConjuncts[:0], 1216 notify: n.notify[:0], 1217 checks: n.checks[:0], 1218 postChecks: n.postChecks[:0], 1219 dynamicFields: n.dynamicFields[:0], 1220 comprehensions: n.comprehensions[:0], 1221 selfComprehensions: n.selfComprehensions[:0], 1222 lists: n.lists[:0], 1223 vLists: n.vLists[:0], 1224 exprs: n.exprs[:0], 1225 disjunctions: n.disjunctions[:0], 1226 disjunctCCs: n.disjunctCCs[:0], 1227 usedDefault: n.usedDefault[:0], 1228 disjunctErrs: n.disjunctErrs[:0], 1229 disjuncts: n.disjuncts[:0], 1230 buffer: n.buffer[:0], 1231 } 1232 n.scheduler.clear() 1233 n.scheduler.node = n 1234 n.underlying = node 1235 1236 return n 1237 } 1238 c.stats.Allocs++ 1239 1240 n := &nodeContext{ 1241 scheduler: scheduler{ 1242 ctx: c, 1243 }, 1244 node: node, 1245 1246 nodeContextState: nodeContextState{kind: TopKind}, 1247 } 1248 n.scheduler.node = n 1249 n.underlying = node 1250 return n 1251 } 1252 1253 func (v *Vertex) getNodeContext(c *OpContext, ref int) *nodeContext { 1254 unreachableForDev(c) 1255 1256 if v.state == nil { 1257 if v.status == finalized { 1258 return nil 1259 } 1260 v.state = c.newNodeContext(v) 1261 } else if v.state.node != v { 1262 panic("getNodeContext: nodeContext out of sync") 1263 } 1264 v.state.refCount += ref 1265 return v.state 1266 } 1267 1268 func (v *Vertex) freeNode(n *nodeContext) { 1269 if n == nil { 1270 return 1271 } 1272 if n.node != v { 1273 panic("freeNode: unpaired free") 1274 } 1275 if v.state != nil && v.state != n { 1276 panic("freeNode: nodeContext out of sync") 1277 } 1278 if n.refCount--; n.refCount == 0 { 1279 if v.status == finalized { 1280 v.freeNodeState() 1281 } else { 1282 n.ctx.stats.Retained++ 1283 } 1284 } 1285 } 1286 1287 func (v *Vertex) freeNodeState() { 1288 if v.state == nil { 1289 return 1290 } 1291 state := v.state 1292 v.state = nil 1293 1294 state.ctx.freeNodeContext(state) 1295 } 1296 1297 func (n *nodeContext) free() { 1298 if n.refCount--; n.refCount == 0 { 1299 n.ctx.freeNodeContext(n) 1300 } 1301 } 1302 1303 func (c *OpContext) freeNodeContext(n *nodeContext) { 1304 c.stats.Freed++ 1305 n.nextFree = c.freeListNode 1306 c.freeListNode = n 1307 n.node = nil 1308 n.refCount = 0 1309 n.scheduler.clear() 1310 } 1311 1312 // TODO(perf): return a dedicated ConflictError that can track original 1313 // positions on demand. 1314 func (n *nodeContext) reportConflict( 1315 v1, v2 Node, 1316 k1, k2 Kind, 1317 ids ...CloseInfo) { 1318 1319 ctx := n.ctx 1320 1321 var err *ValueError 1322 if k1 == k2 { 1323 err = ctx.NewPosf(token.NoPos, "conflicting values %s and %s", v1, v2) 1324 } else { 1325 err = ctx.NewPosf(token.NoPos, 1326 "conflicting values %s and %s (mismatched types %s and %s)", 1327 v1, v2, k1, k2) 1328 } 1329 1330 err.AddPosition(v1) 1331 err.AddPosition(v2) 1332 for _, id := range ids { 1333 err.AddClosedPositions(id) 1334 } 1335 1336 n.addErr(err) 1337 } 1338 1339 // reportFieldMismatch reports the mixture of regular fields with non-struct 1340 // values. Either s or f needs to be given. 1341 func (n *nodeContext) reportFieldMismatch( 1342 p token.Pos, 1343 s *StructLit, 1344 f Feature, 1345 scalar Expr, 1346 id ...CloseInfo) { 1347 1348 ctx := n.ctx 1349 1350 if f == InvalidLabel { 1351 for _, a := range s.Decls { 1352 if x, ok := a.(*Field); ok && x.Label.IsRegular() { 1353 f = x.Label 1354 p = pos(x) 1355 break 1356 } 1357 } 1358 if f == InvalidLabel { 1359 n.reportConflict(scalar, s, n.kind, StructKind, id...) 1360 return 1361 } 1362 } 1363 1364 err := ctx.NewPosf(p, "cannot combine regular field %q with %v", f, scalar) 1365 1366 if s != nil { 1367 err.AddPosition(s) 1368 } 1369 1370 for _, ci := range id { 1371 err.AddClosedPositions(ci) 1372 } 1373 1374 n.addErr(err) 1375 } 1376 1377 func (n *nodeContext) updateNodeType(k Kind, v Expr, id CloseInfo) bool { 1378 ctx := n.ctx 1379 kind := n.kind & k 1380 1381 switch { 1382 case n.kind == BottomKind, 1383 k == BottomKind: 1384 return false 1385 1386 case kind != BottomKind: 1387 1388 // TODO: we could consider changing the reporting for structs, but this 1389 // makes only sense in case they are for embeddings. Otherwise the type 1390 // of a struct is more relevant for the failure. 1391 // case k == StructKind: 1392 // s, _ := v.(*StructLit) 1393 // n.reportFieldMismatch(token.NoPos, s, 0, n.kindExpr, id, n.kindID) 1394 1395 case n.kindExpr != nil: 1396 n.reportConflict(n.kindExpr, v, n.kind, k, n.kindID, id) 1397 1398 default: 1399 n.addErr(ctx.Newf( 1400 "conflicting value %s (mismatched types %s and %s)", 1401 v, n.kind, k)) 1402 } 1403 1404 if n.kind != kind || n.kindExpr == nil { 1405 n.kindExpr = v 1406 } 1407 n.kind = kind 1408 return kind != BottomKind 1409 } 1410 1411 func (n *nodeContext) done() bool { 1412 // TODO(v0.7): verify that done() is checking for the right conditions in 1413 // the new evaluator implementation. 1414 return len(n.dynamicFields) == 0 && 1415 len(n.comprehensions) == 0 && 1416 len(n.exprs) == 0 1417 } 1418 1419 // finalDone is like done, but allows for cycle errors, which can be ignored 1420 // as they essentially indicate a = a & _. 1421 func (n *nodeContext) finalDone() bool { 1422 // TODO(v0.7): update for new evaluator? 1423 for _, x := range n.exprs { 1424 if x.err.Code != CycleError { 1425 return false 1426 } 1427 } 1428 return len(n.dynamicFields) == 0 && 1429 len(n.comprehensions) == 0 && 1430 len(n.selfComprehensions) == 0 1431 } 1432 1433 // hasErr is used to determine if an evaluation path, for instance a single 1434 // path after expanding all disjunctions, has an error. 1435 func (n *nodeContext) hasErr() bool { 1436 n.assertInitialized() 1437 1438 if n.node.ChildErrors != nil { 1439 return true 1440 } 1441 if n.node.status > evaluating && n.node.IsErr() { 1442 return true 1443 } 1444 return n.ctx.HasErr() || n.errs != nil 1445 } 1446 1447 func (n *nodeContext) getErr() *Bottom { 1448 n.assertInitialized() 1449 1450 n.errs = CombineErrors(nil, n.errs, n.ctx.Err()) 1451 return n.errs 1452 } 1453 1454 // getValidators sets the vertex' Value in case there was no concrete value. 1455 func (n *nodeContext) getValidators(state vertexStatus) BaseValue { 1456 n.assertInitialized() 1457 1458 ctx := n.ctx 1459 1460 a := []Value{} 1461 // if n.node.Value != nil { 1462 // a = append(a, n.node.Value) 1463 // } 1464 kind := TopKind 1465 if n.lowerBound != nil { 1466 a = append(a, n.lowerBound) 1467 kind &= n.lowerBound.Kind() 1468 } 1469 if n.upperBound != nil { 1470 a = append(a, n.upperBound) 1471 kind &= n.upperBound.Kind() 1472 } 1473 for _, c := range n.checks { 1474 // Drop !=x if x is out of bounds with another bound. 1475 if b, _ := c.(*BoundValue); b != nil && b.Op == NotEqualOp { 1476 if n.upperBound != nil && 1477 SimplifyBounds(ctx, n.kind, n.upperBound, b) != nil { 1478 continue 1479 } 1480 if n.lowerBound != nil && 1481 SimplifyBounds(ctx, n.kind, n.lowerBound, b) != nil { 1482 continue 1483 } 1484 } 1485 a = append(a, c) 1486 kind &= c.Kind() 1487 } 1488 1489 if kind&^n.kind != 0 { 1490 a = append(a, &BasicType{ 1491 Src: n.kindExpr.Source(), // TODO:Is this always a BasicType? 1492 K: n.kind, 1493 }) 1494 } 1495 1496 var v BaseValue 1497 switch len(a) { 1498 case 0: 1499 // Src is the combined input. 1500 if state >= conjuncts || n.kind&^CompositeKind == 0 { 1501 v = &BasicType{K: n.kind} 1502 } 1503 1504 case 1: 1505 v = a[0] 1506 1507 default: 1508 v = &Conjunction{Values: a} 1509 } 1510 1511 return v 1512 } 1513 1514 // TODO: this function can probably go as this is now handled in the nodeContext. 1515 func (n *nodeContext) maybeSetCache() { 1516 // Set BaseValue to scalar, but only if it was not set before. Most notably, 1517 // errors should not be discarded. 1518 _, isErr := n.node.BaseValue.(*Bottom) 1519 if n.scalar != nil && (!isErr || isCyclePlaceholder(n.node.BaseValue)) { 1520 n.node.BaseValue = n.scalar 1521 } 1522 // NOTE: this is now handled by associating the nodeContext 1523 // if n.errs != nil { 1524 // n.node.SetValue(n.ctx, Partial, n.errs) 1525 // } 1526 } 1527 1528 type envExpr struct { 1529 c Conjunct 1530 err *Bottom 1531 } 1532 1533 type envDynamic struct { 1534 env *Environment 1535 field *DynamicField 1536 id CloseInfo 1537 err *Bottom 1538 } 1539 1540 type envList struct { 1541 env *Environment 1542 list *ListLit 1543 n int64 // recorded length after evaluator 1544 elipsis *Ellipsis 1545 id CloseInfo 1546 ignore bool // has a self-referencing comprehension and is postponed 1547 self bool // was added as a postponed self-referencing comprehension 1548 index int 1549 } 1550 1551 type envCheck struct { 1552 env *Environment 1553 expr Expr 1554 expectError bool 1555 } 1556 1557 func (n *nodeContext) addBottom(b *Bottom) { 1558 n.assertInitialized() 1559 1560 n.errs = CombineErrors(nil, n.errs, b) 1561 // TODO(errors): consider doing this 1562 // n.kindExpr = n.errs 1563 // n.kind = 0 1564 } 1565 1566 func (n *nodeContext) addErr(err errors.Error) { 1567 n.assertInitialized() 1568 1569 if err != nil { 1570 n.addBottom(&Bottom{Err: err}) 1571 } 1572 } 1573 1574 // addExprConjuncts will attempt to evaluate an Expr and insert the value 1575 // into the nodeContext if successful or queue it for later evaluation if it is 1576 // incomplete or is not value. 1577 func (n *nodeContext) addExprConjunct(v Conjunct, state vertexStatus) { 1578 unreachableForDev(n.ctx) 1579 1580 env := v.Env 1581 id := v.CloseInfo 1582 1583 switch x := v.Elem().(type) { 1584 case *Vertex: 1585 if x.IsData() { 1586 n.addValueConjunct(env, x, id) 1587 } else { 1588 n.addVertexConjuncts(v, x, true) 1589 } 1590 1591 case Value: 1592 n.addValueConjunct(env, x, id) 1593 1594 case *BinaryExpr: 1595 if x.Op == AndOp { 1596 n.addExprConjunct(MakeConjunct(env, x.X, id), state) 1597 n.addExprConjunct(MakeConjunct(env, x.Y, id), state) 1598 return 1599 } else { 1600 n.evalExpr(v, state) 1601 } 1602 1603 case *StructLit: 1604 n.addStruct(env, x, id) 1605 1606 case *ListLit: 1607 childEnv := &Environment{ 1608 Up: env, 1609 Vertex: n.node, 1610 } 1611 n.lists = append(n.lists, envList{env: childEnv, list: x, id: id}) 1612 1613 case *DisjunctionExpr: 1614 n.addDisjunction(env, x, id) 1615 1616 case *Comprehension: 1617 // always a partial comprehension. 1618 n.insertComprehension(env, x, id) 1619 return 1620 1621 default: 1622 // Must be Resolver or Evaluator. 1623 n.evalExpr(v, state) 1624 } 1625 n.ctx.stats.Conjuncts++ 1626 } 1627 1628 // evalExpr is only called by addExprConjunct. If an error occurs, it records 1629 // the error in n and returns nil. 1630 func (n *nodeContext) evalExpr(v Conjunct, state vertexStatus) { 1631 unreachableForDev(n.ctx) 1632 1633 // Require an Environment. 1634 ctx := n.ctx 1635 1636 closeID := v.CloseInfo 1637 1638 switch x := v.Expr().(type) { 1639 case Resolver: 1640 // We elevate a field evaluated to the Conjuncts state to Finalized 1641 // later. For now we allow partial evaluation so that we can break 1642 // cycles and postpone incomplete evaluations until more information is 1643 // available down the line. 1644 if state == finalized { 1645 state = conjuncts 1646 } 1647 arc, err := ctx.resolveState(v, x, oldOnly(state)) 1648 if err != nil && (!err.IsIncomplete() || err.Permanent) { 1649 n.addBottom(err) 1650 break 1651 } 1652 if arc == nil { 1653 n.exprs = append(n.exprs, envExpr{v, err}) 1654 break 1655 } 1656 1657 // We complete the evaluation. Some optimizations will only work when an 1658 // arc is already finalized. So this ensures that such optimizations get 1659 // triggered more often. 1660 // 1661 // NOTE(let finalization): aside from being an optimization, this also 1662 // ensures that let arcs that are not contained as fields of arcs, but 1663 // rather are held in the cash, are finalized. This, in turn, is 1664 // necessary to trigger the notification mechanism, where appropriate. 1665 // 1666 // A node should not Finalize itself as it may erase the state object 1667 // which is still assumed to be present down the line 1668 // (see https://cuelang.org/issues/2171). 1669 if arc.status == conjuncts && arc != n.node && arc.hasAllConjuncts { 1670 arc.Finalize(ctx) 1671 } 1672 1673 ci, skip := n.markCycle(arc, v.Env, x, v.CloseInfo) 1674 if skip { 1675 return 1676 } 1677 v.CloseInfo = ci 1678 1679 n.addVertexConjuncts(v, arc, false) 1680 1681 case Evaluator: 1682 // Interpolation, UnaryExpr, BinaryExpr, CallExpr 1683 // Could be unify? 1684 val := ctx.evaluateRec(v, oldOnly(partial)) 1685 if b, ok := val.(*Bottom); ok && 1686 b.IsIncomplete() { 1687 n.exprs = append(n.exprs, envExpr{v, b}) 1688 break 1689 } 1690 1691 if v, ok := val.(*Vertex); ok { 1692 // Handle generated disjunctions (as in the 'or' builtin). 1693 // These come as a Vertex, but should not be added as a value. 1694 b, ok := v.BaseValue.(*Bottom) 1695 if ok && b.IsIncomplete() && len(v.Conjuncts) > 0 { 1696 for _, c := range v.Conjuncts { 1697 c.CloseInfo = closeID 1698 n.addExprConjunct(c, state) 1699 } 1700 break 1701 } 1702 } 1703 1704 // TODO: also to through normal Vertex handling here. At the moment 1705 // addValueConjunct handles StructMarker.NeedsClose, as this is always 1706 // only needed when evaluation an Evaluator, and not a Resolver. 1707 // The two code paths should ideally be merged once this separate 1708 // mechanism is eliminated. 1709 // 1710 // if arc, ok := val.(*Vertex); ok && !arc.IsData() { 1711 // n.addVertexConjuncts(v.Env, closeID, v.Expr(), arc) 1712 // break 1713 // } 1714 1715 // TODO: insert in vertex as well 1716 n.addValueConjunct(v.Env, val, closeID) 1717 1718 default: 1719 panic(fmt.Sprintf("unknown expression of type %T", x)) 1720 } 1721 } 1722 1723 func (n *nodeContext) addVertexConjuncts(c Conjunct, arc *Vertex, inline bool) { 1724 unreachableForDev(n.ctx) 1725 1726 closeInfo := c.CloseInfo 1727 1728 // We need to ensure that each arc is only unified once (or at least) a 1729 // bounded time, witch each conjunct. Comprehensions, for instance, may 1730 // distribute a value across many values that get unified back into the 1731 // same value. If such a value is a disjunction, than a disjunction of N 1732 // disjuncts will result in a factor N more unifications for each 1733 // occurrence of such value, resulting in exponential running time. This 1734 // is especially common values that are used as a type. 1735 // 1736 // However, unification is idempotent, so each such conjunct only needs 1737 // to be unified once. This cache checks for this and prevents an 1738 // exponential blowup in such case. 1739 // 1740 // TODO(perf): this cache ensures the conjuncts of an arc at most once 1741 // per ID. However, we really need to add the conjuncts of an arc only 1742 // once total, and then add the close information once per close ID 1743 // (pointer can probably be shared). Aside from being more performant, 1744 // this is probably the best way to guarantee that conjunctions are 1745 // linear in this case. 1746 1747 ckey := closeInfo 1748 ckey.Refs = nil 1749 ckey.Inline = false 1750 key := arcKey{arc, ckey} 1751 for _, k := range n.arcMap { 1752 if key == k { 1753 return 1754 } 1755 } 1756 n.arcMap = append(n.arcMap, key) 1757 1758 status := arc.status 1759 1760 switch status { 1761 case evaluating: 1762 // Reference cycle detected. We have reached a fixed point and 1763 // adding conjuncts at this point will not change the value. Also, 1764 // continuing to pursue this value will result in an infinite loop. 1765 1766 // TODO: add a mechanism so that the computation will only have to 1767 // be done once? 1768 1769 if arc == n.node { 1770 // TODO: we could use node sharing here. This may avoid an 1771 // exponential blowup during evaluation, like is possible with 1772 // YAML. 1773 return 1774 } 1775 1776 case evaluatingArcs: 1777 // There is a structural cycle, but values may be processed nonetheless 1778 // if there is a non-cyclic conjunct. See cycle.go. 1779 } 1780 1781 // Performance: the following if check filters cases that are not strictly 1782 // necessary for correct functioning. Not updating the closeInfo may cause 1783 // some position information to be lost for top-level positions of merges 1784 // resulting form APIs. These tend to be fairly uninteresting. 1785 // At the same time, this optimization may prevent considerable slowdown 1786 // in case an API does many calls to Unify. 1787 x := c.Expr() 1788 if !inline || arc.IsClosedStruct() || arc.IsClosedList() { 1789 closeInfo = closeInfo.SpawnRef(arc, IsDef(x), x) 1790 } 1791 1792 if arc.status == unprocessed && !inline { 1793 // This is a rare condition, but can happen in certain 1794 // evaluation orders. Unfortunately, adding this breaks 1795 // resolution of cyclic mutually referring disjunctions. But it 1796 // is necessary to prevent lookups in unevaluated structs. 1797 // TODO(cycles): this can probably most easily be fixed with a 1798 // having a more recursive implementation. 1799 n.ctx.unify(arc, oldOnly(partial)) 1800 } 1801 1802 // Don't add conjuncts if a node is referring to itself. 1803 if n.node == arc { 1804 return 1805 } 1806 1807 if arc.state != nil { 1808 arc.state.addNotify(n.node, nil) 1809 } 1810 1811 for _, c := range arc.Conjuncts { 1812 // Note that we are resetting the tree here. We hereby assume that 1813 // closedness conflicts resulting from unifying the referenced arc were 1814 // already caught there and that we can ignore further errors here. 1815 c.CloseInfo = closeInfo 1816 n.addExprConjunct(c, partial) 1817 } 1818 } 1819 1820 func (n *nodeContext) addValueConjunct(env *Environment, v Value, id CloseInfo) { 1821 n.updateCyclicStatus(id) 1822 1823 ctx := n.ctx 1824 1825 if x, ok := v.(*Vertex); ok { 1826 if m, ok := x.BaseValue.(*StructMarker); ok { 1827 n.aStruct = x 1828 n.aStructID = id 1829 if m.NeedClose { 1830 id.IsClosed = true 1831 } 1832 } 1833 1834 if !x.IsData() { 1835 // TODO: this really shouldn't happen anymore. 1836 if isComplexStruct(ctx, x) { 1837 // This really shouldn't happen, but just in case. 1838 n.addVertexConjuncts(MakeConjunct(env, x, id), x, true) 1839 return 1840 } 1841 1842 for _, c := range x.Conjuncts { 1843 c.CloseInfo = id 1844 n.addExprConjunct(c, partial) // TODO: Pass from eval 1845 } 1846 return 1847 } 1848 1849 // TODO: evaluate value? 1850 switch v := x.BaseValue.(type) { 1851 default: 1852 panic(fmt.Sprintf("invalid type %T", x.BaseValue)) 1853 1854 case *ListMarker: 1855 n.vLists = append(n.vLists, x) 1856 return 1857 1858 case *StructMarker: 1859 1860 case Value: 1861 n.addValueConjunct(env, v, id) 1862 } 1863 1864 if len(x.Arcs) == 0 { 1865 return 1866 } 1867 1868 s := &StructLit{} 1869 1870 // Keep ordering of Go struct for topological sort. 1871 n.node.AddStruct(s, env, id) 1872 n.node.Structs = append(n.node.Structs, x.Structs...) 1873 1874 for _, a := range x.Arcs { 1875 if !a.definitelyExists() { 1876 continue 1877 } 1878 // TODO(errors): report error when this is a regular field. 1879 c := MakeConjunct(nil, a, id) 1880 n.insertField(a.Label, a.ArcType, c) 1881 s.MarkField(a.Label) 1882 } 1883 return 1884 } 1885 1886 switch b := v.(type) { 1887 case *Bottom: 1888 n.addBottom(b) 1889 return 1890 case *Builtin: 1891 if v := b.BareValidator(); v != nil { 1892 n.addValueConjunct(env, v, id) 1893 return 1894 } 1895 } 1896 1897 if !n.updateNodeType(v.Kind(), v, id) { 1898 return 1899 } 1900 1901 switch x := v.(type) { 1902 case *Disjunction: 1903 n.addDisjunctionValue(env, x, id) 1904 1905 case *Conjunction: 1906 for _, x := range x.Values { 1907 n.addValueConjunct(env, x, id) 1908 } 1909 1910 case *Top: 1911 n.hasTop = true 1912 1913 case *BasicType: 1914 // handled above 1915 1916 case *BoundValue: 1917 switch x.Op { 1918 case LessThanOp, LessEqualOp: 1919 if y := n.upperBound; y != nil { 1920 n.upperBound = nil 1921 v := SimplifyBounds(ctx, n.kind, x, y) 1922 if err := valueError(v); err != nil { 1923 err.AddPosition(v) 1924 err.AddPosition(n.upperBound) 1925 err.AddClosedPositions(id) 1926 } 1927 n.addValueConjunct(env, v, id) 1928 return 1929 } 1930 n.upperBound = x 1931 1932 case GreaterThanOp, GreaterEqualOp: 1933 if y := n.lowerBound; y != nil { 1934 n.lowerBound = nil 1935 v := SimplifyBounds(ctx, n.kind, x, y) 1936 if err := valueError(v); err != nil { 1937 err.AddPosition(v) 1938 err.AddPosition(n.lowerBound) 1939 err.AddClosedPositions(id) 1940 } 1941 n.addValueConjunct(env, v, id) 1942 return 1943 } 1944 n.lowerBound = x 1945 1946 case EqualOp, NotEqualOp, MatchOp, NotMatchOp: 1947 // This check serves as simplifier, but also to remove duplicates. 1948 k := 0 1949 match := false 1950 for _, c := range n.checks { 1951 if y, ok := c.(*BoundValue); ok { 1952 switch z := SimplifyBounds(ctx, n.kind, x, y); { 1953 case z == y: 1954 match = true 1955 case z == x: 1956 continue 1957 } 1958 } 1959 n.checks[k] = c 1960 k++ 1961 } 1962 n.checks = n.checks[:k] 1963 if !match { 1964 n.checks = append(n.checks, x) 1965 } 1966 return 1967 } 1968 1969 case Validator: 1970 // This check serves as simplifier, but also to remove duplicates. 1971 for i, y := range n.checks { 1972 if b := SimplifyValidator(ctx, x, y); b != nil { 1973 n.checks[i] = b 1974 return 1975 } 1976 } 1977 n.updateNodeType(x.Kind(), x, id) 1978 n.checks = append(n.checks, x) 1979 1980 case *Vertex: 1981 // handled above. 1982 1983 case Value: // *NullLit, *BoolLit, *NumLit, *StringLit, *BytesLit, *Builtin 1984 if y := n.scalar; y != nil { 1985 if b, ok := BinOp(ctx, EqualOp, x, y).(*Bool); !ok || !b.B { 1986 n.reportConflict(x, y, x.Kind(), y.Kind(), n.scalarID, id) 1987 } 1988 // TODO: do we need to explicitly add again? 1989 // n.scalar = nil 1990 // n.addValueConjunct(c, BinOp(c, EqualOp, x, y)) 1991 break 1992 } 1993 n.scalar = x 1994 n.scalarID = id 1995 if n.node.status >= conjuncts { 1996 n.node.BaseValue = x 1997 } 1998 1999 default: 2000 panic(fmt.Sprintf("unknown value type %T", x)) 2001 } 2002 2003 if n.lowerBound != nil && n.upperBound != nil { 2004 if u := SimplifyBounds(ctx, n.kind, n.lowerBound, n.upperBound); u != nil { 2005 if err := valueError(u); err != nil { 2006 err.AddPosition(n.lowerBound) 2007 err.AddPosition(n.upperBound) 2008 err.AddClosedPositions(id) 2009 } 2010 n.lowerBound = nil 2011 n.upperBound = nil 2012 n.addValueConjunct(env, u, id) 2013 } 2014 } 2015 } 2016 2017 func valueError(v Value) *ValueError { 2018 if v == nil { 2019 return nil 2020 } 2021 b, _ := v.(*Bottom) 2022 if b == nil { 2023 return nil 2024 } 2025 err, _ := b.Err.(*ValueError) 2026 if err == nil { 2027 return nil 2028 } 2029 return err 2030 } 2031 2032 // addStruct collates the declarations of a struct. 2033 // 2034 // addStruct fulfills two additional pivotal functions: 2035 // 1. Implement vertex unification (this happens through De Bruijn indices 2036 // combined with proper set up of Environments). 2037 // 2. Implied closedness for definitions. 2038 func (n *nodeContext) addStruct( 2039 env *Environment, 2040 s *StructLit, 2041 closeInfo CloseInfo) { 2042 2043 n.updateCyclicStatus(closeInfo) 2044 2045 // NOTE: This is a crucial point in the code: 2046 // Unification dereferencing happens here. The child nodes are set to 2047 // an Environment linked to the current node. Together with the De Bruijn 2048 // indices, this determines to which Vertex a reference resolves. 2049 2050 childEnv := &Environment{ 2051 Up: env, 2052 Vertex: n.node, 2053 } 2054 2055 s.Init(n.ctx) 2056 2057 if s.HasEmbed && !s.IsFile() { 2058 closeInfo = closeInfo.SpawnGroup(nil) 2059 } 2060 2061 parent := n.node.AddStruct(s, childEnv, closeInfo) 2062 closeInfo.IsClosed = false 2063 2064 parent.Disable = true // disable until processing is done. 2065 2066 for _, d := range s.Decls { 2067 switch x := d.(type) { 2068 case *Field: 2069 if x.Label.IsString() && x.ArcType == ArcMember { 2070 n.aStruct = s 2071 n.aStructID = closeInfo 2072 } 2073 n.insertField(x.Label, x.ArcType, MakeConjunct(childEnv, x, closeInfo)) 2074 2075 case *LetField: 2076 arc := n.insertField(x.Label, ArcMember, MakeConjunct(childEnv, x, closeInfo)) 2077 if x.IsMulti { 2078 arc.MultiLet = x.IsMulti 2079 } 2080 2081 case *DynamicField: 2082 n.aStruct = s 2083 n.aStructID = closeInfo 2084 n.dynamicFields = append(n.dynamicFields, envDynamic{childEnv, x, closeInfo, nil}) 2085 2086 case *Comprehension: 2087 n.insertComprehension(childEnv, x, closeInfo) 2088 2089 case Expr: 2090 // add embedding to optional 2091 2092 // TODO(perf): only do this if addExprConjunct below will result in 2093 // a fieldSet. Otherwise the entry will just be removed next. 2094 id := closeInfo.SpawnEmbed(x) 2095 2096 c := MakeConjunct(childEnv, x, id) 2097 n.addExprConjunct(c, partial) 2098 2099 case *BulkOptionalField, *Ellipsis: 2100 // Nothing to do here. Note that the presence of these fields do not 2101 // excluded embedded scalars: only when they match actual fields 2102 // does it exclude those. 2103 2104 default: 2105 panic("unreachable") 2106 } 2107 } 2108 2109 if !s.HasEmbed { 2110 n.aStruct = s 2111 n.aStructID = closeInfo 2112 } 2113 2114 parent.Disable = false 2115 2116 } 2117 2118 // TODO(perf): if an arc is the only arc with that label added to a Vertex, and 2119 // if there are no conjuncts of optional fields to be added, then the arc could 2120 // be added as is until any of these conditions change. This would allow 2121 // structure sharing in many cases. One should be careful, however, to 2122 // recursively track arcs of previously unified evaluated vertices ot make this 2123 // optimization meaningful. 2124 // 2125 // An alternative approach to avoid evaluating optional arcs (if we take that 2126 // route) is to not recursively evaluate those arcs, even for Finalize. This is 2127 // possible as it is not necessary to evaluate optional arcs to evaluate 2128 // disjunctions. 2129 func (n *nodeContext) insertField(f Feature, mode ArcType, x Conjunct) *Vertex { 2130 ctx := n.ctx 2131 if ctx.isDevVersion() { 2132 return n.insertArc(f, mode, x, x.CloseInfo, true) 2133 } 2134 2135 arc, isNew := n.node.GetArc(ctx, f, mode) 2136 if f.IsLet() && !isNew { 2137 arc.MultiLet = true 2138 return arc 2139 } 2140 if arc.hasConjunct(x) { 2141 return arc 2142 } 2143 2144 switch { 2145 case arc.state != nil: 2146 arc.state.addConjunctDynamic(x) 2147 2148 case arc.IsUnprocessed() || arc.status != finalized: 2149 arc.addConjunctUnchecked(x) 2150 2151 default: 2152 n.addBottom(&Bottom{ 2153 Code: IncompleteError, 2154 Err: ctx.NewPosf(pos(x.Field()), 2155 "cannot add field %s: was already used", 2156 f.SelectorString(ctx)), 2157 }) 2158 } 2159 return arc 2160 } 2161 2162 func (n *nodeContext) insertFieldUnchecked(f Feature, mode ArcType, x Conjunct) *Vertex { 2163 ctx := n.ctx 2164 if ctx.isDevVersion() { 2165 return n.insertArc(f, mode, x, x.CloseInfo, false) 2166 } 2167 2168 arc, isNew := n.node.GetArc(ctx, f, mode) 2169 if f.IsLet() && !isNew { 2170 arc.MultiLet = true 2171 return arc 2172 } 2173 arc.addConjunctUnchecked(x) 2174 return arc 2175 } 2176 2177 // expandOne adds dynamic fields to a node until a fixed point is reached. 2178 // On each iteration, dynamic fields that cannot resolve due to incomplete 2179 // values are skipped. They will be retried on the next iteration until no 2180 // progress can be made. Note that a dynamic field may add more dynamic fields. 2181 // 2182 // forClauses are processed after all other clauses. A struct may be referenced 2183 // before it is complete, meaning that fields added by other forms of injection 2184 // may influence the result of a for clause _after_ it has already been 2185 // processed. We could instead detect such insertion and feed it to the 2186 // ForClause to generate another entry or have the for clause be recomputed. 2187 // This seems to be too complicated and lead to iffy edge cases. 2188 // TODO(errors): detect when a field is added to a struct that is already used 2189 // in a for clause. 2190 func (n *nodeContext) expandOne(state vertexStatus) (done bool) { 2191 unreachableForDev(n.ctx) 2192 2193 // Don't expand incomplete expressions if we detected a cycle. 2194 if n.done() || (n.hasCycle && !n.hasNonCycle) { 2195 return false 2196 } 2197 2198 var progress bool 2199 2200 if progress = n.injectDynamic(); progress { 2201 return true 2202 } 2203 2204 if progress = n.injectComprehensions(state); progress { 2205 return true 2206 } 2207 2208 // Do expressions after comprehensions, as comprehensions can never 2209 // refer to embedded scalars, whereas expressions may refer to generated 2210 // fields if we were to allow attributes to be defined alongside 2211 // scalars. 2212 exprs := n.exprs 2213 n.exprs = n.exprs[:0] 2214 for _, x := range exprs { 2215 n.addExprConjunct(x.c, state) 2216 2217 // collect and or 2218 } 2219 if len(n.exprs) < len(exprs) { 2220 return true 2221 } 2222 2223 // No progress, report error later if needed: unification with 2224 // disjuncts may resolve this later on. 2225 return false 2226 } 2227 2228 // injectDynamic evaluates and inserts dynamic declarations. 2229 func (n *nodeContext) injectDynamic() (progress bool) { 2230 unreachableForDev(n.ctx) 2231 2232 ctx := n.ctx 2233 k := 0 2234 2235 a := n.dynamicFields 2236 for _, d := range n.dynamicFields { 2237 var f Feature 2238 x := d.field.Key 2239 // Push state to capture and remove errors. 2240 s := ctx.PushState(d.env, x.Source()) 2241 v := ctx.evalState(x, oldOnly(finalized)) 2242 b := ctx.PopState(s) 2243 2244 if b != nil && b.IsIncomplete() { 2245 d.err, _ = v.(*Bottom) 2246 a[k] = d 2247 k++ 2248 continue 2249 } 2250 if b, _ := v.(*Bottom); b != nil { 2251 n.addValueConjunct(nil, b, d.id) 2252 continue 2253 } 2254 f = ctx.Label(d.field.Key, v) 2255 if f.IsInt() { 2256 n.addErr(ctx.NewPosf(pos(d.field.Key), "integer fields not supported")) 2257 } 2258 n.insertField(f, d.field.ArcType, MakeConjunct(d.env, d.field, d.id)) 2259 } 2260 2261 progress = k < len(n.dynamicFields) 2262 2263 n.dynamicFields = a[:k] 2264 2265 return progress 2266 } 2267 2268 // addLists evaluates the queued list conjuncts and inserts its arcs into the 2269 // Vertex. 2270 // 2271 // TODO: association arrays: 2272 // If an association array marker was present in a struct, create a struct node 2273 // instead of a list node. In either case, a node may only have list fields 2274 // or struct fields and not both. 2275 // 2276 // addLists should be run after the fixpoint expansion: 2277 // - it enforces that comprehensions may not refer to the list itself 2278 // - there may be no other fields within the list. 2279 // 2280 // TODO(embeddedScalars): for embedded scalars, there should be another pass 2281 // of evaluation expressions after expanding lists. 2282 func (n *nodeContext) addLists(state combinedFlags) (progress bool) { 2283 if len(n.lists) == 0 && len(n.vLists) == 0 { 2284 return false 2285 } 2286 2287 var oneOfTheLists Expr 2288 var anID CloseInfo 2289 2290 isOpen := true 2291 max := 0 2292 var maxNode Expr 2293 2294 if m, ok := n.node.BaseValue.(*ListMarker); ok { 2295 isOpen = m.IsOpen 2296 max = len(n.node.Arcs) 2297 } 2298 2299 c := n.ctx 2300 2301 for _, l := range n.vLists { 2302 // XXX: set hasNonCycle if appropriate. 2303 2304 oneOfTheLists = l 2305 2306 elems := l.Elems() 2307 isClosed := l.IsClosedList() 2308 2309 switch { 2310 case len(elems) < max: 2311 if isClosed { 2312 n.invalidListLength(len(elems), max, l, maxNode) 2313 continue 2314 } 2315 2316 case len(elems) > max: 2317 if !isOpen { 2318 n.invalidListLength(max, len(elems), maxNode, l) 2319 continue 2320 } 2321 isOpen = !isClosed 2322 max = len(elems) 2323 maxNode = l 2324 2325 case isClosed: 2326 isOpen = false 2327 maxNode = l 2328 } 2329 2330 for _, a := range elems { 2331 if a.Conjuncts == nil { 2332 n.insertField(a.Label, ArcMember, MakeRootConjunct(nil, a)) 2333 continue 2334 } 2335 for _, c := range a.Conjuncts { 2336 n.insertField(a.Label, ArcMember, c) 2337 } 2338 } 2339 } 2340 2341 outer: 2342 // updateCyclicStatus may grow the list of values, so we cannot use range. 2343 for i := 0; i < len(n.lists); i++ { 2344 l := n.lists[i] 2345 2346 n.updateCyclicStatus(l.id) 2347 2348 if l.self { 2349 n.node.LockArcs = true 2350 } 2351 2352 index := int64(0) 2353 hasComprehension := false 2354 for j, elem := range l.list.Elems { 2355 switch x := elem.(type) { 2356 case *Comprehension: 2357 err := c.yield(nil, l.env, x, state, func(e *Environment) { 2358 label, err := MakeLabel(x.Source(), index, IntLabel) 2359 n.addErr(err) 2360 index++ 2361 c := MakeConjunct(e, x.Value, l.id) 2362 n.insertField(label, ArcMember, c) 2363 }) 2364 hasComprehension = true 2365 if err != nil { 2366 if err.ForCycle && !l.self { 2367 // The list has a comprehension that refers to the list 2368 // itself. This means we should postpone evaluating this 2369 // list until all other lists have been evaluated. 2370 n.lists[i].ignore = true 2371 l.self = true 2372 n.lists = append(n.lists, l) 2373 } else { 2374 n.addBottom(err) 2375 } 2376 continue outer 2377 } 2378 2379 case *Ellipsis: 2380 if j != len(l.list.Elems)-1 { 2381 n.addErr(c.Newf("ellipsis must be last element in list")) 2382 } 2383 2384 n.lists[i].elipsis = x 2385 2386 default: 2387 label, err := MakeLabel(x.Source(), index, IntLabel) 2388 n.addErr(err) 2389 index++ // TODO: don't use insertField. 2390 n.insertField(label, ArcMember, MakeConjunct(l.env, x, l.id)) 2391 } 2392 2393 // Terminate early in case of runaway comprehension. 2394 if !isOpen && int(index) > max { 2395 n.invalidListLength(max, len(l.list.Elems), maxNode, l.list) 2396 continue outer 2397 } 2398 } 2399 2400 oneOfTheLists = l.list 2401 anID = l.id 2402 2403 switch closed := n.lists[i].elipsis == nil; { 2404 case int(index) < max: 2405 if closed { 2406 n.invalidListLength(int(index), max, l.list, maxNode) 2407 continue 2408 } 2409 2410 case int(index) > max, 2411 closed && isOpen, 2412 (!closed == isOpen) && !hasComprehension: 2413 max = int(index) 2414 maxNode = l.list 2415 isOpen = !closed 2416 } 2417 2418 n.lists[i].n = index 2419 } 2420 2421 // add additionalItem values to list and construct optionals. 2422 elems := n.node.Elems() 2423 for _, l := range n.vLists { 2424 if !l.IsClosedList() { 2425 continue 2426 } 2427 2428 newElems := l.Elems() 2429 if len(newElems) >= len(elems) { 2430 continue // error generated earlier, if applicable. 2431 } 2432 2433 for _, arc := range elems[len(newElems):] { 2434 l.MatchAndInsert(c, arc) 2435 } 2436 } 2437 2438 for _, l := range n.lists { 2439 if l.elipsis == nil || l.ignore { 2440 continue 2441 } 2442 2443 s := l.list.info 2444 if s == nil { 2445 s = &StructLit{Decls: []Decl{l.elipsis}} 2446 s.Init(n.ctx) 2447 l.list.info = s 2448 } 2449 info := n.node.AddStruct(s, l.env, l.id) 2450 2451 for _, arc := range elems[l.n:] { 2452 info.MatchAndInsert(c, arc) 2453 } 2454 } 2455 2456 sources := []ast.Expr{} 2457 // Add conjuncts for additional items. 2458 for _, l := range n.lists { 2459 if l.elipsis == nil || l.ignore { 2460 continue 2461 } 2462 if src, _ := l.elipsis.Source().(ast.Expr); src != nil { 2463 sources = append(sources, src) 2464 } 2465 } 2466 2467 if m, ok := n.node.BaseValue.(*ListMarker); !ok { 2468 n.node.setValue(c, partial, &ListMarker{ 2469 Src: ast.NewBinExpr(token.AND, sources...), 2470 IsOpen: isOpen, 2471 }) 2472 } else { 2473 if expr, _ := m.Src.(ast.Expr); expr != nil { 2474 sources = append(sources, expr) 2475 } 2476 m.Src = ast.NewBinExpr(token.AND, sources...) 2477 m.IsOpen = m.IsOpen && isOpen 2478 } 2479 2480 n.lists = n.lists[:0] 2481 n.vLists = n.vLists[:0] 2482 2483 n.updateNodeType(ListKind, oneOfTheLists, anID) 2484 2485 return true 2486 } 2487 2488 func (n *nodeContext) invalidListLength(na, nb int, a, b Expr) { 2489 n.addErr(n.ctx.Newf("incompatible list lengths (%d and %d)", na, nb)) 2490 }