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