github.com/hashicorp/hcl/v2@v2.20.0/hclsyntax/expression.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package hclsyntax 5 6 import ( 7 "fmt" 8 "sort" 9 "strings" 10 "sync" 11 12 "github.com/hashicorp/hcl/v2" 13 "github.com/hashicorp/hcl/v2/ext/customdecode" 14 "github.com/zclconf/go-cty/cty" 15 "github.com/zclconf/go-cty/cty/convert" 16 "github.com/zclconf/go-cty/cty/function" 17 ) 18 19 // Expression is the abstract type for nodes that behave as HCL expressions. 20 type Expression interface { 21 Node 22 23 // The hcl.Expression methods are duplicated here, rather than simply 24 // embedded, because both Node and hcl.Expression have a Range method 25 // and so they conflict. 26 27 Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) 28 Variables() []hcl.Traversal 29 StartRange() hcl.Range 30 } 31 32 // Assert that Expression implements hcl.Expression 33 var _ hcl.Expression = Expression(nil) 34 35 // ParenthesesExpr represents an expression written in grouping 36 // parentheses. 37 // 38 // The parser takes care of the precedence effect of the parentheses, so the 39 // only purpose of this separate expression node is to capture the source range 40 // of the parentheses themselves, rather than the source range of the 41 // expression within. All of the other expression operations just pass through 42 // to the underlying expression. 43 type ParenthesesExpr struct { 44 Expression 45 SrcRange hcl.Range 46 } 47 48 var _ hcl.Expression = (*ParenthesesExpr)(nil) 49 50 func (e *ParenthesesExpr) Range() hcl.Range { 51 return e.SrcRange 52 } 53 54 func (e *ParenthesesExpr) walkChildNodes(w internalWalkFunc) { 55 // We override the walkChildNodes from the embedded Expression to 56 // ensure that both the parentheses _and_ the content are visible 57 // in a walk. 58 w(e.Expression) 59 } 60 61 // LiteralValueExpr is an expression that just always returns a given value. 62 type LiteralValueExpr struct { 63 Val cty.Value 64 SrcRange hcl.Range 65 } 66 67 func (e *LiteralValueExpr) walkChildNodes(w internalWalkFunc) { 68 // Literal values have no child nodes 69 } 70 71 func (e *LiteralValueExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 72 return e.Val, nil 73 } 74 75 func (e *LiteralValueExpr) Range() hcl.Range { 76 return e.SrcRange 77 } 78 79 func (e *LiteralValueExpr) StartRange() hcl.Range { 80 return e.SrcRange 81 } 82 83 // Implementation for hcl.AbsTraversalForExpr. 84 func (e *LiteralValueExpr) AsTraversal() hcl.Traversal { 85 // This one's a little weird: the contract for AsTraversal is to interpret 86 // an expression as if it were traversal syntax, and traversal syntax 87 // doesn't have the special keywords "null", "true", and "false" so these 88 // are expected to be treated like variables in that case. 89 // Since our parser already turned them into LiteralValueExpr by the time 90 // we get here, we need to undo this and infer the name that would've 91 // originally led to our value. 92 // We don't do anything for any other values, since they don't overlap 93 // with traversal roots. 94 95 if e.Val.IsNull() { 96 // In practice the parser only generates null values of the dynamic 97 // pseudo-type for literals, so we can safely assume that any null 98 // was orignally the keyword "null". 99 return hcl.Traversal{ 100 hcl.TraverseRoot{ 101 Name: "null", 102 SrcRange: e.SrcRange, 103 }, 104 } 105 } 106 107 switch e.Val { 108 case cty.True: 109 return hcl.Traversal{ 110 hcl.TraverseRoot{ 111 Name: "true", 112 SrcRange: e.SrcRange, 113 }, 114 } 115 case cty.False: 116 return hcl.Traversal{ 117 hcl.TraverseRoot{ 118 Name: "false", 119 SrcRange: e.SrcRange, 120 }, 121 } 122 default: 123 // No traversal is possible for any other value. 124 return nil 125 } 126 } 127 128 // ScopeTraversalExpr is an Expression that retrieves a value from the scope 129 // using a traversal. 130 type ScopeTraversalExpr struct { 131 Traversal hcl.Traversal 132 SrcRange hcl.Range 133 } 134 135 func (e *ScopeTraversalExpr) walkChildNodes(w internalWalkFunc) { 136 // Scope traversals have no child nodes 137 } 138 139 func (e *ScopeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 140 val, diags := e.Traversal.TraverseAbs(ctx) 141 setDiagEvalContext(diags, e, ctx) 142 return val, diags 143 } 144 145 func (e *ScopeTraversalExpr) Range() hcl.Range { 146 return e.SrcRange 147 } 148 149 func (e *ScopeTraversalExpr) StartRange() hcl.Range { 150 return e.SrcRange 151 } 152 153 // Implementation for hcl.AbsTraversalForExpr. 154 func (e *ScopeTraversalExpr) AsTraversal() hcl.Traversal { 155 return e.Traversal 156 } 157 158 // RelativeTraversalExpr is an Expression that retrieves a value from another 159 // value using a _relative_ traversal. 160 type RelativeTraversalExpr struct { 161 Source Expression 162 Traversal hcl.Traversal 163 SrcRange hcl.Range 164 } 165 166 func (e *RelativeTraversalExpr) walkChildNodes(w internalWalkFunc) { 167 w(e.Source) 168 } 169 170 func (e *RelativeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 171 src, diags := e.Source.Value(ctx) 172 ret, travDiags := e.Traversal.TraverseRel(src) 173 setDiagEvalContext(travDiags, e, ctx) 174 diags = append(diags, travDiags...) 175 return ret, diags 176 } 177 178 func (e *RelativeTraversalExpr) Range() hcl.Range { 179 return e.SrcRange 180 } 181 182 func (e *RelativeTraversalExpr) StartRange() hcl.Range { 183 return e.SrcRange 184 } 185 186 // Implementation for hcl.AbsTraversalForExpr. 187 func (e *RelativeTraversalExpr) AsTraversal() hcl.Traversal { 188 // We can produce a traversal only if our source can. 189 st, diags := hcl.AbsTraversalForExpr(e.Source) 190 if diags.HasErrors() { 191 return nil 192 } 193 194 ret := make(hcl.Traversal, len(st)+len(e.Traversal)) 195 copy(ret, st) 196 copy(ret[len(st):], e.Traversal) 197 return ret 198 } 199 200 // FunctionCallExpr is an Expression that calls a function from the EvalContext 201 // and returns its result. 202 type FunctionCallExpr struct { 203 Name string 204 Args []Expression 205 206 // If true, the final argument should be a tuple, list or set which will 207 // expand to be one argument per element. 208 ExpandFinal bool 209 210 NameRange hcl.Range 211 OpenParenRange hcl.Range 212 CloseParenRange hcl.Range 213 } 214 215 func (e *FunctionCallExpr) walkChildNodes(w internalWalkFunc) { 216 for _, arg := range e.Args { 217 w(arg) 218 } 219 } 220 221 func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 222 var diags hcl.Diagnostics 223 224 var f function.Function 225 exists := false 226 hasNonNilMap := false 227 thisCtx := ctx 228 for thisCtx != nil { 229 if thisCtx.Functions == nil { 230 thisCtx = thisCtx.Parent() 231 continue 232 } 233 hasNonNilMap = true 234 f, exists = thisCtx.Functions[e.Name] 235 if exists { 236 break 237 } 238 thisCtx = thisCtx.Parent() 239 } 240 241 if !exists { 242 if !hasNonNilMap { 243 return cty.DynamicVal, hcl.Diagnostics{ 244 { 245 Severity: hcl.DiagError, 246 Summary: "Function calls not allowed", 247 Detail: "Functions may not be called here.", 248 Subject: e.Range().Ptr(), 249 Expression: e, 250 EvalContext: ctx, 251 }, 252 } 253 } 254 255 extraUnknown := &functionCallUnknown{ 256 name: e.Name, 257 } 258 259 // For historical reasons, we represent namespaced function names 260 // as strings with :: separating the names. If this was an attempt 261 // to call a namespaced function then we'll try to distinguish 262 // between an invalid namespace or an invalid name within a valid 263 // namespace in order to give the user better feedback about what 264 // is wrong. 265 // 266 // The parser guarantees that a function name will always 267 // be a series of valid identifiers separated by "::" with no 268 // other content, so we can be relatively unforgiving in our processing 269 // here. 270 if sepIdx := strings.LastIndex(e.Name, "::"); sepIdx != -1 { 271 namespace := e.Name[:sepIdx+2] 272 name := e.Name[sepIdx+2:] 273 274 avail := make([]string, 0, len(ctx.Functions)) 275 for availName := range ctx.Functions { 276 if strings.HasPrefix(availName, namespace) { 277 avail = append(avail, availName) 278 } 279 } 280 281 extraUnknown.name = name 282 extraUnknown.namespace = namespace 283 284 if len(avail) == 0 { 285 // TODO: Maybe use nameSuggestion for the other available 286 // namespaces? But that'd require us to go scan the function 287 // table again, so we'll wait to see if it's really warranted. 288 // For now, we're assuming people are more likely to misremember 289 // the function names than the namespaces, because in many 290 // applications there will be relatively few namespaces compared 291 // to the number of distinct functions. 292 return cty.DynamicVal, hcl.Diagnostics{ 293 { 294 Severity: hcl.DiagError, 295 Summary: "Call to unknown function", 296 Detail: fmt.Sprintf("There are no functions in namespace %q.", namespace), 297 Subject: &e.NameRange, 298 Context: e.Range().Ptr(), 299 Expression: e, 300 EvalContext: ctx, 301 Extra: extraUnknown, 302 }, 303 } 304 } else { 305 suggestion := nameSuggestion(name, avail) 306 if suggestion != "" { 307 suggestion = fmt.Sprintf(" Did you mean %s%s?", namespace, suggestion) 308 } 309 310 return cty.DynamicVal, hcl.Diagnostics{ 311 { 312 Severity: hcl.DiagError, 313 Summary: "Call to unknown function", 314 Detail: fmt.Sprintf("There is no function named %q in namespace %s.%s", name, namespace, suggestion), 315 Subject: &e.NameRange, 316 Context: e.Range().Ptr(), 317 Expression: e, 318 EvalContext: ctx, 319 Extra: extraUnknown, 320 }, 321 } 322 } 323 } 324 325 avail := make([]string, 0, len(ctx.Functions)) 326 for name := range ctx.Functions { 327 avail = append(avail, name) 328 } 329 suggestion := nameSuggestion(e.Name, avail) 330 if suggestion != "" { 331 suggestion = fmt.Sprintf(" Did you mean %q?", suggestion) 332 } 333 334 return cty.DynamicVal, hcl.Diagnostics{ 335 { 336 Severity: hcl.DiagError, 337 Summary: "Call to unknown function", 338 Detail: fmt.Sprintf("There is no function named %q.%s", e.Name, suggestion), 339 Subject: &e.NameRange, 340 Context: e.Range().Ptr(), 341 Expression: e, 342 EvalContext: ctx, 343 Extra: extraUnknown, 344 }, 345 } 346 } 347 348 diagExtra := functionCallDiagExtra{ 349 calledFunctionName: e.Name, 350 } 351 352 params := f.Params() 353 varParam := f.VarParam() 354 355 args := e.Args 356 if e.ExpandFinal { 357 if len(args) < 1 { 358 // should never happen if the parser is behaving 359 panic("ExpandFinal set on function call with no arguments") 360 } 361 expandExpr := args[len(args)-1] 362 expandVal, expandDiags := expandExpr.Value(ctx) 363 diags = append(diags, expandDiags...) 364 if expandDiags.HasErrors() { 365 return cty.DynamicVal, diags 366 } 367 368 switch { 369 case expandVal.Type().Equals(cty.DynamicPseudoType): 370 if expandVal.IsNull() { 371 diags = append(diags, &hcl.Diagnostic{ 372 Severity: hcl.DiagError, 373 Summary: "Invalid expanding argument value", 374 Detail: "The expanding argument (indicated by ...) must not be null.", 375 Subject: expandExpr.Range().Ptr(), 376 Context: e.Range().Ptr(), 377 Expression: expandExpr, 378 EvalContext: ctx, 379 Extra: &diagExtra, 380 }) 381 return cty.DynamicVal, diags 382 } 383 return cty.DynamicVal, diags 384 case expandVal.Type().IsTupleType() || expandVal.Type().IsListType() || expandVal.Type().IsSetType(): 385 if expandVal.IsNull() { 386 diags = append(diags, &hcl.Diagnostic{ 387 Severity: hcl.DiagError, 388 Summary: "Invalid expanding argument value", 389 Detail: "The expanding argument (indicated by ...) must not be null.", 390 Subject: expandExpr.Range().Ptr(), 391 Context: e.Range().Ptr(), 392 Expression: expandExpr, 393 EvalContext: ctx, 394 Extra: &diagExtra, 395 }) 396 return cty.DynamicVal, diags 397 } 398 if !expandVal.IsKnown() { 399 return cty.DynamicVal, diags 400 } 401 402 // When expanding arguments from a collection, we must first unmark 403 // the collection itself, and apply any marks directly to the 404 // elements. This ensures that marks propagate correctly. 405 expandVal, marks := expandVal.Unmark() 406 newArgs := make([]Expression, 0, (len(args)-1)+expandVal.LengthInt()) 407 newArgs = append(newArgs, args[:len(args)-1]...) 408 it := expandVal.ElementIterator() 409 for it.Next() { 410 _, val := it.Element() 411 newArgs = append(newArgs, &LiteralValueExpr{ 412 Val: val.WithMarks(marks), 413 SrcRange: expandExpr.Range(), 414 }) 415 } 416 args = newArgs 417 default: 418 diags = append(diags, &hcl.Diagnostic{ 419 Severity: hcl.DiagError, 420 Summary: "Invalid expanding argument value", 421 Detail: "The expanding argument (indicated by ...) must be of a tuple, list, or set type.", 422 Subject: expandExpr.Range().Ptr(), 423 Context: e.Range().Ptr(), 424 Expression: expandExpr, 425 EvalContext: ctx, 426 Extra: &diagExtra, 427 }) 428 return cty.DynamicVal, diags 429 } 430 } 431 432 if len(args) < len(params) { 433 missing := params[len(args)] 434 qual := "" 435 if varParam != nil { 436 qual = " at least" 437 } 438 return cty.DynamicVal, hcl.Diagnostics{ 439 { 440 Severity: hcl.DiagError, 441 Summary: "Not enough function arguments", 442 Detail: fmt.Sprintf( 443 "Function %q expects%s %d argument(s). Missing value for %q.", 444 e.Name, qual, len(params), missing.Name, 445 ), 446 Subject: &e.CloseParenRange, 447 Context: e.Range().Ptr(), 448 Expression: e, 449 EvalContext: ctx, 450 Extra: &diagExtra, 451 }, 452 } 453 } 454 455 if varParam == nil && len(args) > len(params) { 456 return cty.DynamicVal, hcl.Diagnostics{ 457 { 458 Severity: hcl.DiagError, 459 Summary: "Too many function arguments", 460 Detail: fmt.Sprintf( 461 "Function %q expects only %d argument(s).", 462 e.Name, len(params), 463 ), 464 Subject: args[len(params)].StartRange().Ptr(), 465 Context: e.Range().Ptr(), 466 Expression: e, 467 EvalContext: ctx, 468 Extra: &diagExtra, 469 }, 470 } 471 } 472 473 argVals := make([]cty.Value, len(args)) 474 475 for i, argExpr := range args { 476 var param *function.Parameter 477 if i < len(params) { 478 param = ¶ms[i] 479 } else { 480 param = varParam 481 } 482 483 var val cty.Value 484 if decodeFn := customdecode.CustomExpressionDecoderForType(param.Type); decodeFn != nil { 485 var argDiags hcl.Diagnostics 486 val, argDiags = decodeFn(argExpr, ctx) 487 diags = append(diags, argDiags...) 488 if val == cty.NilVal { 489 val = cty.UnknownVal(param.Type) 490 } 491 } else { 492 var argDiags hcl.Diagnostics 493 val, argDiags = argExpr.Value(ctx) 494 if len(argDiags) > 0 { 495 diags = append(diags, argDiags...) 496 } 497 498 // Try to convert our value to the parameter type 499 var err error 500 val, err = convert.Convert(val, param.Type) 501 if err != nil { 502 diags = append(diags, &hcl.Diagnostic{ 503 Severity: hcl.DiagError, 504 Summary: "Invalid function argument", 505 Detail: fmt.Sprintf( 506 "Invalid value for %q parameter: %s.", 507 param.Name, err, 508 ), 509 Subject: argExpr.StartRange().Ptr(), 510 Context: e.Range().Ptr(), 511 Expression: argExpr, 512 EvalContext: ctx, 513 Extra: &diagExtra, 514 }) 515 } 516 } 517 518 argVals[i] = val 519 } 520 521 if diags.HasErrors() { 522 // Don't try to execute the function if we already have errors with 523 // the arguments, because the result will probably be a confusing 524 // error message. 525 return cty.DynamicVal, diags 526 } 527 528 resultVal, err := f.Call(argVals) 529 if err != nil { 530 // For errors in the underlying call itself we also return the raw 531 // call error via an extra method on our "diagnostic extra" value. 532 diagExtra.functionCallError = err 533 534 switch terr := err.(type) { 535 case function.ArgError: 536 i := terr.Index 537 var param *function.Parameter 538 if i < len(params) { 539 param = ¶ms[i] 540 } else { 541 param = varParam 542 } 543 544 if param == nil || i > len(args)-1 { 545 // Getting here means that the function we called has a bug: 546 // it returned an arg error that refers to an argument index 547 // that wasn't present in the call. For that situation 548 // we'll degrade to a less specific error just to give 549 // some sort of answer, but best to still fix the buggy 550 // function so that it only returns argument indices that 551 // are in range. 552 switch { 553 case param != nil: 554 // In this case we'll assume that the function was trying 555 // to talk about a final variadic parameter but the caller 556 // didn't actually provide any arguments for it. That means 557 // we can at least still name the parameter in the 558 // error message, but our source range will be the call 559 // as a whole because we don't have an argument expression 560 // to highlight specifically. 561 diags = append(diags, &hcl.Diagnostic{ 562 Severity: hcl.DiagError, 563 Summary: "Invalid function argument", 564 Detail: fmt.Sprintf( 565 "Invalid value for %q parameter: %s.", 566 param.Name, err, 567 ), 568 Subject: e.Range().Ptr(), 569 Expression: e, 570 EvalContext: ctx, 571 Extra: &diagExtra, 572 }) 573 default: 574 // This is the most degenerate case of all, where the 575 // index is out of range even for the declared parameters, 576 // and so we can't tell which parameter the function is 577 // trying to report an error for. Just a generic error 578 // report in that case. 579 diags = append(diags, &hcl.Diagnostic{ 580 Severity: hcl.DiagError, 581 Summary: "Error in function call", 582 Detail: fmt.Sprintf( 583 "Call to function %q failed: %s.", 584 e.Name, err, 585 ), 586 Subject: e.StartRange().Ptr(), 587 Context: e.Range().Ptr(), 588 Expression: e, 589 EvalContext: ctx, 590 Extra: &diagExtra, 591 }) 592 } 593 } else { 594 argExpr := args[i] 595 596 // TODO: we should also unpick a PathError here and show the 597 // path to the deep value where the error was detected. 598 diags = append(diags, &hcl.Diagnostic{ 599 Severity: hcl.DiagError, 600 Summary: "Invalid function argument", 601 Detail: fmt.Sprintf( 602 "Invalid value for %q parameter: %s.", 603 param.Name, err, 604 ), 605 Subject: argExpr.StartRange().Ptr(), 606 Context: e.Range().Ptr(), 607 Expression: argExpr, 608 EvalContext: ctx, 609 Extra: &diagExtra, 610 }) 611 } 612 613 default: 614 diags = append(diags, &hcl.Diagnostic{ 615 Severity: hcl.DiagError, 616 Summary: "Error in function call", 617 Detail: fmt.Sprintf( 618 "Call to function %q failed: %s.", 619 e.Name, err, 620 ), 621 Subject: e.StartRange().Ptr(), 622 Context: e.Range().Ptr(), 623 Expression: e, 624 EvalContext: ctx, 625 Extra: &diagExtra, 626 }) 627 } 628 629 return cty.DynamicVal, diags 630 } 631 632 return resultVal, diags 633 } 634 635 func (e *FunctionCallExpr) Range() hcl.Range { 636 return hcl.RangeBetween(e.NameRange, e.CloseParenRange) 637 } 638 639 func (e *FunctionCallExpr) StartRange() hcl.Range { 640 return hcl.RangeBetween(e.NameRange, e.OpenParenRange) 641 } 642 643 // Implementation for hcl.ExprCall. 644 func (e *FunctionCallExpr) ExprCall() *hcl.StaticCall { 645 ret := &hcl.StaticCall{ 646 Name: e.Name, 647 NameRange: e.NameRange, 648 Arguments: make([]hcl.Expression, len(e.Args)), 649 ArgsRange: hcl.RangeBetween(e.OpenParenRange, e.CloseParenRange), 650 } 651 // Need to convert our own Expression objects into hcl.Expression. 652 for i, arg := range e.Args { 653 ret.Arguments[i] = arg 654 } 655 return ret 656 } 657 658 // FunctionCallDiagExtra is an interface implemented by the value in the "Extra" 659 // field of some diagnostics returned by FunctionCallExpr.Value, giving 660 // cooperating callers access to some machine-readable information about the 661 // call that a diagnostic relates to. 662 type FunctionCallDiagExtra interface { 663 // CalledFunctionName returns the name of the function being called at 664 // the time the diagnostic was generated, if any. Returns an empty string 665 // if there is no known called function. 666 CalledFunctionName() string 667 668 // FunctionCallError returns the error value returned by the implementation 669 // of the function being called, if any. Returns nil if the diagnostic was 670 // not returned in response to a call error. 671 // 672 // Some errors related to calling functions are generated by HCL itself 673 // rather than by the underlying function, in which case this method 674 // will return nil. 675 FunctionCallError() error 676 } 677 678 type functionCallDiagExtra struct { 679 calledFunctionName string 680 functionCallError error 681 } 682 683 func (e *functionCallDiagExtra) CalledFunctionName() string { 684 return e.calledFunctionName 685 } 686 687 func (e *functionCallDiagExtra) FunctionCallError() error { 688 return e.functionCallError 689 } 690 691 // FunctionCallUnknownDiagExtra is an interface implemented by a value in the Extra 692 // field of some diagnostics to indicate when the error was caused by a call to 693 // an unknown function. 694 type FunctionCallUnknownDiagExtra interface { 695 CalledFunctionName() string 696 CalledFunctionNamespace() string 697 } 698 699 type functionCallUnknown struct { 700 name string 701 namespace string 702 } 703 704 func (e *functionCallUnknown) CalledFunctionName() string { 705 return e.name 706 } 707 708 func (e *functionCallUnknown) CalledFunctionNamespace() string { 709 return e.namespace 710 } 711 712 type ConditionalExpr struct { 713 Condition Expression 714 TrueResult Expression 715 FalseResult Expression 716 717 SrcRange hcl.Range 718 } 719 720 func (e *ConditionalExpr) walkChildNodes(w internalWalkFunc) { 721 w(e.Condition) 722 w(e.TrueResult) 723 w(e.FalseResult) 724 } 725 726 func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 727 trueResult, trueDiags := e.TrueResult.Value(ctx) 728 falseResult, falseDiags := e.FalseResult.Value(ctx) 729 var diags hcl.Diagnostics 730 731 resultType := cty.DynamicPseudoType 732 convs := make([]convert.Conversion, 2) 733 734 switch { 735 // If either case is a dynamic null value (which would result from a 736 // literal null in the config), we know that it can convert to the expected 737 // type of the opposite case, and we don't need to speculatively reduce the 738 // final result type to DynamicPseudoType. 739 740 // If we know that either Type is a DynamicPseudoType, we can be certain 741 // that the other value can convert since it's a pass-through, and we don't 742 // need to unify the types. If the final evaluation results in the dynamic 743 // value being returned, there's no conversion we can do, so we return the 744 // value directly. 745 case trueResult.RawEquals(cty.NullVal(cty.DynamicPseudoType)): 746 resultType = falseResult.Type() 747 convs[0] = convert.GetConversionUnsafe(cty.DynamicPseudoType, resultType) 748 case falseResult.RawEquals(cty.NullVal(cty.DynamicPseudoType)): 749 resultType = trueResult.Type() 750 convs[1] = convert.GetConversionUnsafe(cty.DynamicPseudoType, resultType) 751 case trueResult.Type() == cty.DynamicPseudoType, falseResult.Type() == cty.DynamicPseudoType: 752 // the final resultType type is still unknown 753 // we don't need to get the conversion, because both are a noop. 754 755 default: 756 // Try to find a type that both results can be converted to. 757 resultType, convs = convert.UnifyUnsafe([]cty.Type{trueResult.Type(), falseResult.Type()}) 758 } 759 760 if resultType == cty.NilType { 761 return cty.DynamicVal, hcl.Diagnostics{ 762 { 763 Severity: hcl.DiagError, 764 Summary: "Inconsistent conditional result types", 765 Detail: fmt.Sprintf( 766 "The true and false result expressions must have consistent types. %s.", 767 describeConditionalTypeMismatch(trueResult.Type(), falseResult.Type()), 768 ), 769 Subject: hcl.RangeBetween(e.TrueResult.Range(), e.FalseResult.Range()).Ptr(), 770 Context: &e.SrcRange, 771 Expression: e, 772 EvalContext: ctx, 773 }, 774 } 775 } 776 777 condResult, condDiags := e.Condition.Value(ctx) 778 diags = append(diags, condDiags...) 779 if condResult.IsNull() { 780 diags = append(diags, &hcl.Diagnostic{ 781 Severity: hcl.DiagError, 782 Summary: "Null condition", 783 Detail: "The condition value is null. Conditions must either be true or false.", 784 Subject: e.Condition.Range().Ptr(), 785 Context: &e.SrcRange, 786 Expression: e.Condition, 787 EvalContext: ctx, 788 }) 789 return cty.UnknownVal(resultType), diags 790 } 791 if !condResult.IsKnown() { 792 // we use the unmarked values throughout the unknown branch 793 _, condResultMarks := condResult.Unmark() 794 trueResult, trueResultMarks := trueResult.Unmark() 795 falseResult, falseResultMarks := falseResult.Unmark() 796 797 // use a value to merge marks 798 _, resMarks := cty.DynamicVal.WithMarks(condResultMarks, trueResultMarks, falseResultMarks).Unmark() 799 800 trueRange := trueResult.Range() 801 falseRange := falseResult.Range() 802 803 // if both branches are known to be null, then the result must still be null 804 if trueResult.IsNull() && falseResult.IsNull() { 805 return cty.NullVal(resultType).WithMarks(resMarks), diags 806 } 807 808 // We might be able to offer a refined range for the result based on 809 // the two possible outcomes. 810 if trueResult.Type() == cty.Number && falseResult.Type() == cty.Number { 811 ref := cty.UnknownVal(cty.Number).Refine() 812 if trueRange.DefinitelyNotNull() && falseRange.DefinitelyNotNull() { 813 ref = ref.NotNull() 814 } 815 816 falseLo, falseLoInc := falseRange.NumberLowerBound() 817 falseHi, falseHiInc := falseRange.NumberUpperBound() 818 trueLo, trueLoInc := trueRange.NumberLowerBound() 819 trueHi, trueHiInc := trueRange.NumberUpperBound() 820 821 if falseLo.IsKnown() && trueLo.IsKnown() { 822 lo, loInc := falseLo, falseLoInc 823 switch { 824 case trueLo.LessThan(falseLo).True(): 825 lo, loInc = trueLo, trueLoInc 826 case trueLo.Equals(falseLo).True(): 827 loInc = trueLoInc || falseLoInc 828 } 829 830 ref = ref.NumberRangeLowerBound(lo, loInc) 831 } 832 833 if falseHi.IsKnown() && trueHi.IsKnown() { 834 hi, hiInc := falseHi, falseHiInc 835 switch { 836 case trueHi.GreaterThan(falseHi).True(): 837 hi, hiInc = trueHi, trueHiInc 838 case trueHi.Equals(falseHi).True(): 839 hiInc = trueHiInc || falseHiInc 840 } 841 ref = ref.NumberRangeUpperBound(hi, hiInc) 842 } 843 844 return ref.NewValue().WithMarks(resMarks), diags 845 } 846 847 if trueResult.Type().IsCollectionType() && falseResult.Type().IsCollectionType() { 848 if trueResult.Type().Equals(falseResult.Type()) { 849 ref := cty.UnknownVal(resultType).Refine() 850 if trueRange.DefinitelyNotNull() && falseRange.DefinitelyNotNull() { 851 ref = ref.NotNull() 852 } 853 854 falseLo := falseRange.LengthLowerBound() 855 falseHi := falseRange.LengthUpperBound() 856 trueLo := trueRange.LengthLowerBound() 857 trueHi := trueRange.LengthUpperBound() 858 859 lo := falseLo 860 if trueLo < falseLo { 861 lo = trueLo 862 } 863 864 hi := falseHi 865 if trueHi > falseHi { 866 hi = trueHi 867 } 868 869 ref = ref.CollectionLengthLowerBound(lo).CollectionLengthUpperBound(hi) 870 return ref.NewValue().WithMarks(resMarks), diags 871 } 872 } 873 874 ret := cty.UnknownVal(resultType) 875 if trueRange.DefinitelyNotNull() && falseRange.DefinitelyNotNull() { 876 ret = ret.RefineNotNull() 877 } 878 return ret.WithMarks(resMarks), diags 879 } 880 881 condResult, err := convert.Convert(condResult, cty.Bool) 882 if err != nil { 883 diags = append(diags, &hcl.Diagnostic{ 884 Severity: hcl.DiagError, 885 Summary: "Incorrect condition type", 886 Detail: "The condition expression must be of type bool.", 887 Subject: e.Condition.Range().Ptr(), 888 Context: &e.SrcRange, 889 Expression: e.Condition, 890 EvalContext: ctx, 891 }) 892 return cty.UnknownVal(resultType), diags 893 } 894 895 // Unmark result before testing for truthiness 896 condResult, _ = condResult.UnmarkDeep() 897 if condResult.True() { 898 diags = append(diags, trueDiags...) 899 if convs[0] != nil { 900 var err error 901 trueResult, err = convs[0](trueResult) 902 if err != nil { 903 // Unsafe conversion failed with the concrete result value 904 diags = append(diags, &hcl.Diagnostic{ 905 Severity: hcl.DiagError, 906 Summary: "Inconsistent conditional result types", 907 Detail: fmt.Sprintf( 908 "The true result value has the wrong type: %s.", 909 err.Error(), 910 ), 911 Subject: e.TrueResult.Range().Ptr(), 912 Context: &e.SrcRange, 913 Expression: e.TrueResult, 914 EvalContext: ctx, 915 }) 916 trueResult = cty.UnknownVal(resultType) 917 } 918 } 919 return trueResult, diags 920 } else { 921 diags = append(diags, falseDiags...) 922 if convs[1] != nil { 923 var err error 924 falseResult, err = convs[1](falseResult) 925 if err != nil { 926 // Unsafe conversion failed with the concrete result value 927 diags = append(diags, &hcl.Diagnostic{ 928 Severity: hcl.DiagError, 929 Summary: "Inconsistent conditional result types", 930 Detail: fmt.Sprintf( 931 "The false result value has the wrong type: %s.", 932 err.Error(), 933 ), 934 Subject: e.FalseResult.Range().Ptr(), 935 Context: &e.SrcRange, 936 Expression: e.FalseResult, 937 EvalContext: ctx, 938 }) 939 falseResult = cty.UnknownVal(resultType) 940 } 941 } 942 return falseResult, diags 943 } 944 } 945 946 // describeConditionalTypeMismatch makes a best effort to describe the 947 // difference between types in the true and false arms of a conditional 948 // expression in a way that would be useful to someone trying to understand 949 // why their conditional expression isn't valid. 950 // 951 // NOTE: This function is only designed to deal with situations 952 // where trueTy and falseTy are different. Calling it with two equal 953 // types will produce a nonsense result. This function also only really 954 // deals with situations that type unification can't resolve, so we should 955 // call this function only after trying type unification first. 956 func describeConditionalTypeMismatch(trueTy, falseTy cty.Type) string { 957 // The main tricky cases here are when both trueTy and falseTy are 958 // of the same structural type kind, such as both being object types 959 // or both being tuple types. In that case the "FriendlyName" method 960 // returns only "object" or "tuple" and so we need to do some more 961 // work to describe what's different inside them. 962 963 switch { 964 case trueTy.IsObjectType() && falseTy.IsObjectType(): 965 // We'll first gather up the attribute names and sort them. In the 966 // event that there are multiple attributes that disagree across 967 // the two types, we'll prefer to report the one that sorts lexically 968 // least just so that our error message is consistent between 969 // evaluations. 970 var trueAttrs, falseAttrs []string 971 for name := range trueTy.AttributeTypes() { 972 trueAttrs = append(trueAttrs, name) 973 } 974 sort.Strings(trueAttrs) 975 for name := range falseTy.AttributeTypes() { 976 falseAttrs = append(falseAttrs, name) 977 } 978 sort.Strings(falseAttrs) 979 980 for _, name := range trueAttrs { 981 if !falseTy.HasAttribute(name) { 982 return fmt.Sprintf("The 'true' value includes object attribute %q, which is absent in the 'false' value", name) 983 } 984 trueAty := trueTy.AttributeType(name) 985 falseAty := falseTy.AttributeType(name) 986 if !trueAty.Equals(falseAty) { 987 // For deeply-nested differences this will likely get very 988 // clunky quickly by nesting these messages inside one another, 989 // but we'll accept that for now in the interests of producing 990 // _some_ useful feedback, even if it isn't as concise as 991 // we'd prefer it to be. Deeply-nested structures in 992 // conditionals are thankfully not super common. 993 return fmt.Sprintf( 994 "Type mismatch for object attribute %q: %s", 995 name, describeConditionalTypeMismatch(trueAty, falseAty), 996 ) 997 } 998 } 999 for _, name := range falseAttrs { 1000 if !trueTy.HasAttribute(name) { 1001 return fmt.Sprintf("The 'false' value includes object attribute %q, which is absent in the 'true' value", name) 1002 } 1003 // NOTE: We don't need to check the attribute types again, because 1004 // any attribute that both types have in common would already have 1005 // been checked in the previous loop. 1006 } 1007 case trueTy.IsTupleType() && falseTy.IsTupleType(): 1008 trueEtys := trueTy.TupleElementTypes() 1009 falseEtys := falseTy.TupleElementTypes() 1010 1011 if trueCount, falseCount := len(trueEtys), len(falseEtys); trueCount != falseCount { 1012 return fmt.Sprintf("The 'true' tuple has length %d, but the 'false' tuple has length %d", trueCount, falseCount) 1013 } 1014 1015 // NOTE: Thanks to the condition above, we know that both tuples are 1016 // of the same length and so they must have some differing types 1017 // instead. 1018 for i := range trueEtys { 1019 trueEty := trueEtys[i] 1020 falseEty := falseEtys[i] 1021 1022 if !trueEty.Equals(falseEty) { 1023 // For deeply-nested differences this will likely get very 1024 // clunky quickly by nesting these messages inside one another, 1025 // but we'll accept that for now in the interests of producing 1026 // _some_ useful feedback, even if it isn't as concise as 1027 // we'd prefer it to be. Deeply-nested structures in 1028 // conditionals are thankfully not super common. 1029 return fmt.Sprintf( 1030 "Type mismatch for tuple element %d: %s", 1031 i, describeConditionalTypeMismatch(trueEty, falseEty), 1032 ) 1033 } 1034 } 1035 case trueTy.IsCollectionType() && falseTy.IsCollectionType(): 1036 // For this case we're specifically interested in the situation where: 1037 // - both collections are of the same kind, AND 1038 // - the element types of both are either object or tuple types. 1039 // This is just to avoid writing a useless statement like 1040 // "The 'true' value is list of object, but the 'false' value is list of object". 1041 // This still doesn't account for more awkward cases like collections 1042 // of collections of structural types, but we won't let perfect be 1043 // the enemy of the good. 1044 trueEty := trueTy.ElementType() 1045 falseEty := falseTy.ElementType() 1046 if (trueTy.IsListType() && falseTy.IsListType()) || (trueTy.IsMapType() && falseTy.IsMapType()) || (trueTy.IsSetType() && falseTy.IsSetType()) { 1047 if (trueEty.IsObjectType() && falseEty.IsObjectType()) || (trueEty.IsTupleType() && falseEty.IsTupleType()) { 1048 noun := "collection" 1049 switch { // NOTE: We now know that trueTy and falseTy have the same collection kind 1050 case trueTy.IsListType(): 1051 noun = "list" 1052 case trueTy.IsSetType(): 1053 noun = "set" 1054 case trueTy.IsMapType(): 1055 noun = "map" 1056 } 1057 return fmt.Sprintf( 1058 "Mismatched %s element types: %s", 1059 noun, describeConditionalTypeMismatch(trueEty, falseEty), 1060 ) 1061 } 1062 } 1063 } 1064 1065 // If we don't manage any more specialized message, we'll just report 1066 // what the two types are. 1067 trueName := trueTy.FriendlyName() 1068 falseName := falseTy.FriendlyName() 1069 if trueName == falseName { 1070 // Absolute last resort for when we have no special rule above but 1071 // we have two types with the same friendly name anyway. This is 1072 // the most vague of all possible messages but is reserved for 1073 // particularly awkward cases, like lists of lists of differing tuple 1074 // types. 1075 return "At least one deeply-nested attribute or element is not compatible across both the 'true' and the 'false' value" 1076 } 1077 return fmt.Sprintf( 1078 "The 'true' value is %s, but the 'false' value is %s", 1079 trueTy.FriendlyName(), falseTy.FriendlyName(), 1080 ) 1081 1082 } 1083 1084 func (e *ConditionalExpr) Range() hcl.Range { 1085 return e.SrcRange 1086 } 1087 1088 func (e *ConditionalExpr) StartRange() hcl.Range { 1089 return e.Condition.StartRange() 1090 } 1091 1092 type IndexExpr struct { 1093 Collection Expression 1094 Key Expression 1095 1096 SrcRange hcl.Range 1097 OpenRange hcl.Range 1098 BracketRange hcl.Range 1099 } 1100 1101 func (e *IndexExpr) walkChildNodes(w internalWalkFunc) { 1102 w(e.Collection) 1103 w(e.Key) 1104 } 1105 1106 func (e *IndexExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 1107 var diags hcl.Diagnostics 1108 coll, collDiags := e.Collection.Value(ctx) 1109 key, keyDiags := e.Key.Value(ctx) 1110 diags = append(diags, collDiags...) 1111 diags = append(diags, keyDiags...) 1112 1113 val, indexDiags := hcl.Index(coll, key, &e.BracketRange) 1114 setDiagEvalContext(indexDiags, e, ctx) 1115 diags = append(diags, indexDiags...) 1116 return val, diags 1117 } 1118 1119 func (e *IndexExpr) Range() hcl.Range { 1120 return e.SrcRange 1121 } 1122 1123 func (e *IndexExpr) StartRange() hcl.Range { 1124 return e.OpenRange 1125 } 1126 1127 type TupleConsExpr struct { 1128 Exprs []Expression 1129 1130 SrcRange hcl.Range 1131 OpenRange hcl.Range 1132 } 1133 1134 func (e *TupleConsExpr) walkChildNodes(w internalWalkFunc) { 1135 for _, expr := range e.Exprs { 1136 w(expr) 1137 } 1138 } 1139 1140 func (e *TupleConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 1141 var vals []cty.Value 1142 var diags hcl.Diagnostics 1143 1144 vals = make([]cty.Value, len(e.Exprs)) 1145 for i, expr := range e.Exprs { 1146 val, valDiags := expr.Value(ctx) 1147 vals[i] = val 1148 diags = append(diags, valDiags...) 1149 } 1150 1151 return cty.TupleVal(vals), diags 1152 } 1153 1154 func (e *TupleConsExpr) Range() hcl.Range { 1155 return e.SrcRange 1156 } 1157 1158 func (e *TupleConsExpr) StartRange() hcl.Range { 1159 return e.OpenRange 1160 } 1161 1162 // Implementation for hcl.ExprList 1163 func (e *TupleConsExpr) ExprList() []hcl.Expression { 1164 ret := make([]hcl.Expression, len(e.Exprs)) 1165 for i, expr := range e.Exprs { 1166 ret[i] = expr 1167 } 1168 return ret 1169 } 1170 1171 type ObjectConsExpr struct { 1172 Items []ObjectConsItem 1173 1174 SrcRange hcl.Range 1175 OpenRange hcl.Range 1176 } 1177 1178 type ObjectConsItem struct { 1179 KeyExpr Expression 1180 ValueExpr Expression 1181 } 1182 1183 func (e *ObjectConsExpr) walkChildNodes(w internalWalkFunc) { 1184 for _, item := range e.Items { 1185 w(item.KeyExpr) 1186 w(item.ValueExpr) 1187 } 1188 } 1189 1190 func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 1191 var vals map[string]cty.Value 1192 var diags hcl.Diagnostics 1193 var marks []cty.ValueMarks 1194 1195 // This will get set to true if we fail to produce any of our keys, 1196 // either because they are actually unknown or if the evaluation produces 1197 // errors. In all of these case we must return DynamicPseudoType because 1198 // we're unable to know the full set of keys our object has, and thus 1199 // we can't produce a complete value of the intended type. 1200 // 1201 // We still evaluate all of the item keys and values to make sure that we 1202 // get as complete as possible a set of diagnostics. 1203 known := true 1204 1205 vals = make(map[string]cty.Value, len(e.Items)) 1206 for _, item := range e.Items { 1207 key, keyDiags := item.KeyExpr.Value(ctx) 1208 diags = append(diags, keyDiags...) 1209 1210 val, valDiags := item.ValueExpr.Value(ctx) 1211 diags = append(diags, valDiags...) 1212 1213 if keyDiags.HasErrors() { 1214 known = false 1215 continue 1216 } 1217 1218 if key.IsNull() { 1219 diags = append(diags, &hcl.Diagnostic{ 1220 Severity: hcl.DiagError, 1221 Summary: "Null value as key", 1222 Detail: "Can't use a null value as a key.", 1223 Subject: item.ValueExpr.Range().Ptr(), 1224 Expression: item.KeyExpr, 1225 EvalContext: ctx, 1226 }) 1227 known = false 1228 continue 1229 } 1230 1231 key, keyMarks := key.Unmark() 1232 marks = append(marks, keyMarks) 1233 1234 var err error 1235 key, err = convert.Convert(key, cty.String) 1236 if err != nil { 1237 diags = append(diags, &hcl.Diagnostic{ 1238 Severity: hcl.DiagError, 1239 Summary: "Incorrect key type", 1240 Detail: fmt.Sprintf("Can't use this value as a key: %s.", err.Error()), 1241 Subject: item.KeyExpr.Range().Ptr(), 1242 Expression: item.KeyExpr, 1243 EvalContext: ctx, 1244 }) 1245 known = false 1246 continue 1247 } 1248 1249 if !key.IsKnown() { 1250 known = false 1251 continue 1252 } 1253 1254 keyStr := key.AsString() 1255 1256 vals[keyStr] = val 1257 } 1258 1259 if !known { 1260 return cty.DynamicVal, diags 1261 } 1262 1263 return cty.ObjectVal(vals).WithMarks(marks...), diags 1264 } 1265 1266 func (e *ObjectConsExpr) Range() hcl.Range { 1267 return e.SrcRange 1268 } 1269 1270 func (e *ObjectConsExpr) StartRange() hcl.Range { 1271 return e.OpenRange 1272 } 1273 1274 // Implementation for hcl.ExprMap 1275 func (e *ObjectConsExpr) ExprMap() []hcl.KeyValuePair { 1276 ret := make([]hcl.KeyValuePair, len(e.Items)) 1277 for i, item := range e.Items { 1278 ret[i] = hcl.KeyValuePair{ 1279 Key: item.KeyExpr, 1280 Value: item.ValueExpr, 1281 } 1282 } 1283 return ret 1284 } 1285 1286 // ObjectConsKeyExpr is a special wrapper used only for ObjectConsExpr keys, 1287 // which deals with the special case that a naked identifier in that position 1288 // must be interpreted as a literal string rather than evaluated directly. 1289 type ObjectConsKeyExpr struct { 1290 Wrapped Expression 1291 ForceNonLiteral bool 1292 } 1293 1294 func (e *ObjectConsKeyExpr) literalName() string { 1295 // This is our logic for deciding whether to behave like a literal string. 1296 // We lean on our AbsTraversalForExpr implementation here, which already 1297 // deals with some awkward cases like the expression being the result 1298 // of the keywords "null", "true" and "false" which we'd want to interpret 1299 // as keys here too. 1300 return hcl.ExprAsKeyword(e.Wrapped) 1301 } 1302 1303 func (e *ObjectConsKeyExpr) walkChildNodes(w internalWalkFunc) { 1304 // We only treat our wrapped expression as a real expression if we're 1305 // not going to interpret it as a literal. 1306 if e.literalName() == "" { 1307 w(e.Wrapped) 1308 } 1309 } 1310 1311 func (e *ObjectConsKeyExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 1312 // Because we accept a naked identifier as a literal key rather than a 1313 // reference, it's confusing to accept a traversal containing periods 1314 // here since we can't tell if the user intends to create a key with 1315 // periods or actually reference something. To avoid confusing downstream 1316 // errors we'll just prohibit a naked multi-step traversal here and 1317 // require the user to state their intent more clearly. 1318 // (This is handled at evaluation time rather than parse time because 1319 // an application using static analysis _can_ accept a naked multi-step 1320 // traversal here, if desired.) 1321 if !e.ForceNonLiteral { 1322 if travExpr, isTraversal := e.Wrapped.(*ScopeTraversalExpr); isTraversal && len(travExpr.Traversal) > 1 { 1323 var diags hcl.Diagnostics 1324 diags = append(diags, &hcl.Diagnostic{ 1325 Severity: hcl.DiagError, 1326 Summary: "Ambiguous attribute key", 1327 Detail: "If this expression is intended to be a reference, wrap it in parentheses. If it's instead intended as a literal name containing periods, wrap it in quotes to create a string literal.", 1328 Subject: e.Range().Ptr(), 1329 }) 1330 return cty.DynamicVal, diags 1331 } 1332 1333 if ln := e.literalName(); ln != "" { 1334 return cty.StringVal(ln), nil 1335 } 1336 } 1337 return e.Wrapped.Value(ctx) 1338 } 1339 1340 func (e *ObjectConsKeyExpr) Range() hcl.Range { 1341 return e.Wrapped.Range() 1342 } 1343 1344 func (e *ObjectConsKeyExpr) StartRange() hcl.Range { 1345 return e.Wrapped.StartRange() 1346 } 1347 1348 // Implementation for hcl.AbsTraversalForExpr. 1349 func (e *ObjectConsKeyExpr) AsTraversal() hcl.Traversal { 1350 // If we're forcing a non-literal then we can never be interpreted 1351 // as a traversal. 1352 if e.ForceNonLiteral { 1353 return nil 1354 } 1355 1356 // We can produce a traversal only if our wrappee can. 1357 st, diags := hcl.AbsTraversalForExpr(e.Wrapped) 1358 if diags.HasErrors() { 1359 return nil 1360 } 1361 1362 return st 1363 } 1364 1365 func (e *ObjectConsKeyExpr) UnwrapExpression() Expression { 1366 return e.Wrapped 1367 } 1368 1369 // ForExpr represents iteration constructs: 1370 // 1371 // tuple = [for i, v in list: upper(v) if i > 2] 1372 // object = {for k, v in map: k => upper(v)} 1373 // object_of_tuples = {for v in list: v.key: v...} 1374 type ForExpr struct { 1375 KeyVar string // empty if ignoring the key 1376 ValVar string 1377 1378 CollExpr Expression 1379 1380 KeyExpr Expression // nil when producing a tuple 1381 ValExpr Expression 1382 CondExpr Expression // null if no "if" clause is present 1383 1384 Group bool // set if the ellipsis is used on the value in an object for 1385 1386 SrcRange hcl.Range 1387 OpenRange hcl.Range 1388 CloseRange hcl.Range 1389 } 1390 1391 func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 1392 var diags hcl.Diagnostics 1393 var marks []cty.ValueMarks 1394 1395 collVal, collDiags := e.CollExpr.Value(ctx) 1396 diags = append(diags, collDiags...) 1397 1398 if collVal.IsNull() { 1399 diags = append(diags, &hcl.Diagnostic{ 1400 Severity: hcl.DiagError, 1401 Summary: "Iteration over null value", 1402 Detail: "A null value cannot be used as the collection in a 'for' expression.", 1403 Subject: e.CollExpr.Range().Ptr(), 1404 Context: &e.SrcRange, 1405 Expression: e.CollExpr, 1406 EvalContext: ctx, 1407 }) 1408 return cty.DynamicVal, diags 1409 } 1410 if collVal.Type() == cty.DynamicPseudoType { 1411 return cty.DynamicVal, diags 1412 } 1413 // Unmark collection before checking for iterability, because marked 1414 // values cannot be iterated 1415 collVal, collMarks := collVal.Unmark() 1416 marks = append(marks, collMarks) 1417 if !collVal.CanIterateElements() { 1418 diags = append(diags, &hcl.Diagnostic{ 1419 Severity: hcl.DiagError, 1420 Summary: "Iteration over non-iterable value", 1421 Detail: fmt.Sprintf( 1422 "A value of type %s cannot be used as the collection in a 'for' expression.", 1423 collVal.Type().FriendlyName(), 1424 ), 1425 Subject: e.CollExpr.Range().Ptr(), 1426 Context: &e.SrcRange, 1427 Expression: e.CollExpr, 1428 EvalContext: ctx, 1429 }) 1430 return cty.DynamicVal, diags 1431 } 1432 if !collVal.IsKnown() { 1433 return cty.DynamicVal, diags 1434 } 1435 1436 // Before we start we'll do an early check to see if any CondExpr we've 1437 // been given is of the wrong type. This isn't 100% reliable (it may 1438 // be DynamicVal until real values are given) but it should catch some 1439 // straightforward cases and prevent a barrage of repeated errors. 1440 if e.CondExpr != nil { 1441 childCtx := ctx.NewChild() 1442 childCtx.Variables = map[string]cty.Value{} 1443 if e.KeyVar != "" { 1444 childCtx.Variables[e.KeyVar] = cty.DynamicVal 1445 } 1446 childCtx.Variables[e.ValVar] = cty.DynamicVal 1447 1448 result, condDiags := e.CondExpr.Value(childCtx) 1449 diags = append(diags, condDiags...) 1450 if result.IsNull() { 1451 diags = append(diags, &hcl.Diagnostic{ 1452 Severity: hcl.DiagError, 1453 Summary: "Condition is null", 1454 Detail: "The value of the 'if' clause must not be null.", 1455 Subject: e.CondExpr.Range().Ptr(), 1456 Context: &e.SrcRange, 1457 Expression: e.CondExpr, 1458 EvalContext: ctx, 1459 }) 1460 return cty.DynamicVal, diags 1461 } 1462 _, err := convert.Convert(result, cty.Bool) 1463 if err != nil { 1464 diags = append(diags, &hcl.Diagnostic{ 1465 Severity: hcl.DiagError, 1466 Summary: "Invalid 'for' condition", 1467 Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()), 1468 Subject: e.CondExpr.Range().Ptr(), 1469 Context: &e.SrcRange, 1470 Expression: e.CondExpr, 1471 EvalContext: ctx, 1472 }) 1473 return cty.DynamicVal, diags 1474 } 1475 if condDiags.HasErrors() { 1476 return cty.DynamicVal, diags 1477 } 1478 } 1479 1480 if e.KeyExpr != nil { 1481 // Producing an object 1482 var vals map[string]cty.Value 1483 var groupVals map[string][]cty.Value 1484 if e.Group { 1485 groupVals = map[string][]cty.Value{} 1486 } else { 1487 vals = map[string]cty.Value{} 1488 } 1489 1490 it := collVal.ElementIterator() 1491 1492 known := true 1493 for it.Next() { 1494 k, v := it.Element() 1495 childCtx := ctx.NewChild() 1496 childCtx.Variables = map[string]cty.Value{} 1497 if e.KeyVar != "" { 1498 childCtx.Variables[e.KeyVar] = k 1499 } 1500 childCtx.Variables[e.ValVar] = v 1501 1502 if e.CondExpr != nil { 1503 includeRaw, condDiags := e.CondExpr.Value(childCtx) 1504 diags = append(diags, condDiags...) 1505 if includeRaw.IsNull() { 1506 if known { 1507 diags = append(diags, &hcl.Diagnostic{ 1508 Severity: hcl.DiagError, 1509 Summary: "Invalid 'for' condition", 1510 Detail: "The value of the 'if' clause must not be null.", 1511 Subject: e.CondExpr.Range().Ptr(), 1512 Context: &e.SrcRange, 1513 Expression: e.CondExpr, 1514 EvalContext: childCtx, 1515 }) 1516 } 1517 known = false 1518 continue 1519 } 1520 include, err := convert.Convert(includeRaw, cty.Bool) 1521 if err != nil { 1522 if known { 1523 diags = append(diags, &hcl.Diagnostic{ 1524 Severity: hcl.DiagError, 1525 Summary: "Invalid 'for' condition", 1526 Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()), 1527 Subject: e.CondExpr.Range().Ptr(), 1528 Context: &e.SrcRange, 1529 Expression: e.CondExpr, 1530 EvalContext: childCtx, 1531 }) 1532 } 1533 known = false 1534 continue 1535 } 1536 if !include.IsKnown() { 1537 known = false 1538 continue 1539 } 1540 1541 // Extract and merge marks from the include expression into the 1542 // main set of marks 1543 includeUnmarked, includeMarks := include.Unmark() 1544 marks = append(marks, includeMarks) 1545 if includeUnmarked.False() { 1546 // Skip this element 1547 continue 1548 } 1549 } 1550 1551 keyRaw, keyDiags := e.KeyExpr.Value(childCtx) 1552 diags = append(diags, keyDiags...) 1553 if keyRaw.IsNull() { 1554 if known { 1555 diags = append(diags, &hcl.Diagnostic{ 1556 Severity: hcl.DiagError, 1557 Summary: "Invalid object key", 1558 Detail: "Key expression in 'for' expression must not produce a null value.", 1559 Subject: e.KeyExpr.Range().Ptr(), 1560 Context: &e.SrcRange, 1561 Expression: e.KeyExpr, 1562 EvalContext: childCtx, 1563 }) 1564 } 1565 known = false 1566 continue 1567 } 1568 if !keyRaw.IsKnown() { 1569 known = false 1570 continue 1571 } 1572 1573 key, err := convert.Convert(keyRaw, cty.String) 1574 if err != nil { 1575 if known { 1576 diags = append(diags, &hcl.Diagnostic{ 1577 Severity: hcl.DiagError, 1578 Summary: "Invalid object key", 1579 Detail: fmt.Sprintf("The key expression produced an invalid result: %s.", err.Error()), 1580 Subject: e.KeyExpr.Range().Ptr(), 1581 Context: &e.SrcRange, 1582 Expression: e.KeyExpr, 1583 EvalContext: childCtx, 1584 }) 1585 } 1586 known = false 1587 continue 1588 } 1589 1590 key, keyMarks := key.Unmark() 1591 marks = append(marks, keyMarks) 1592 1593 val, valDiags := e.ValExpr.Value(childCtx) 1594 diags = append(diags, valDiags...) 1595 1596 if e.Group { 1597 k := key.AsString() 1598 groupVals[k] = append(groupVals[k], val) 1599 } else { 1600 k := key.AsString() 1601 if _, exists := vals[k]; exists { 1602 diags = append(diags, &hcl.Diagnostic{ 1603 Severity: hcl.DiagError, 1604 Summary: "Duplicate object key", 1605 Detail: fmt.Sprintf( 1606 "Two different items produced the key %q in this 'for' expression. If duplicates are expected, use the ellipsis (...) after the value expression to enable grouping by key.", 1607 k, 1608 ), 1609 Subject: e.KeyExpr.Range().Ptr(), 1610 Context: &e.SrcRange, 1611 Expression: e.KeyExpr, 1612 EvalContext: childCtx, 1613 }) 1614 } else { 1615 vals[key.AsString()] = val 1616 } 1617 } 1618 } 1619 1620 if !known { 1621 return cty.DynamicVal, diags 1622 } 1623 1624 if e.Group { 1625 vals = map[string]cty.Value{} 1626 for k, gvs := range groupVals { 1627 vals[k] = cty.TupleVal(gvs) 1628 } 1629 } 1630 1631 return cty.ObjectVal(vals).WithMarks(marks...), diags 1632 1633 } else { 1634 // Producing a tuple 1635 vals := []cty.Value{} 1636 1637 it := collVal.ElementIterator() 1638 1639 known := true 1640 for it.Next() { 1641 k, v := it.Element() 1642 childCtx := ctx.NewChild() 1643 childCtx.Variables = map[string]cty.Value{} 1644 if e.KeyVar != "" { 1645 childCtx.Variables[e.KeyVar] = k 1646 } 1647 childCtx.Variables[e.ValVar] = v 1648 1649 if e.CondExpr != nil { 1650 includeRaw, condDiags := e.CondExpr.Value(childCtx) 1651 diags = append(diags, condDiags...) 1652 if includeRaw.IsNull() { 1653 if known { 1654 diags = append(diags, &hcl.Diagnostic{ 1655 Severity: hcl.DiagError, 1656 Summary: "Invalid 'for' condition", 1657 Detail: "The value of the 'if' clause must not be null.", 1658 Subject: e.CondExpr.Range().Ptr(), 1659 Context: &e.SrcRange, 1660 Expression: e.CondExpr, 1661 EvalContext: childCtx, 1662 }) 1663 } 1664 known = false 1665 continue 1666 } 1667 if !includeRaw.IsKnown() { 1668 // We will eventually return DynamicVal, but we'll continue 1669 // iterating in case there are other diagnostics to gather 1670 // for later elements. 1671 known = false 1672 continue 1673 } 1674 1675 include, err := convert.Convert(includeRaw, cty.Bool) 1676 if err != nil { 1677 if known { 1678 diags = append(diags, &hcl.Diagnostic{ 1679 Severity: hcl.DiagError, 1680 Summary: "Invalid 'for' condition", 1681 Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()), 1682 Subject: e.CondExpr.Range().Ptr(), 1683 Context: &e.SrcRange, 1684 Expression: e.CondExpr, 1685 EvalContext: childCtx, 1686 }) 1687 } 1688 known = false 1689 continue 1690 } 1691 1692 // Extract and merge marks from the include expression into the 1693 // main set of marks 1694 includeUnmarked, includeMarks := include.Unmark() 1695 marks = append(marks, includeMarks) 1696 if includeUnmarked.False() { 1697 // Skip this element 1698 continue 1699 } 1700 } 1701 1702 val, valDiags := e.ValExpr.Value(childCtx) 1703 diags = append(diags, valDiags...) 1704 vals = append(vals, val) 1705 } 1706 1707 if !known { 1708 return cty.DynamicVal, diags 1709 } 1710 1711 return cty.TupleVal(vals).WithMarks(marks...), diags 1712 } 1713 } 1714 1715 func (e *ForExpr) walkChildNodes(w internalWalkFunc) { 1716 w(e.CollExpr) 1717 1718 scopeNames := map[string]struct{}{} 1719 if e.KeyVar != "" { 1720 scopeNames[e.KeyVar] = struct{}{} 1721 } 1722 if e.ValVar != "" { 1723 scopeNames[e.ValVar] = struct{}{} 1724 } 1725 1726 if e.KeyExpr != nil { 1727 w(ChildScope{ 1728 LocalNames: scopeNames, 1729 Expr: e.KeyExpr, 1730 }) 1731 } 1732 w(ChildScope{ 1733 LocalNames: scopeNames, 1734 Expr: e.ValExpr, 1735 }) 1736 if e.CondExpr != nil { 1737 w(ChildScope{ 1738 LocalNames: scopeNames, 1739 Expr: e.CondExpr, 1740 }) 1741 } 1742 } 1743 1744 func (e *ForExpr) Range() hcl.Range { 1745 return e.SrcRange 1746 } 1747 1748 func (e *ForExpr) StartRange() hcl.Range { 1749 return e.OpenRange 1750 } 1751 1752 type SplatExpr struct { 1753 Source Expression 1754 Each Expression 1755 Item *AnonSymbolExpr 1756 1757 SrcRange hcl.Range 1758 MarkerRange hcl.Range 1759 } 1760 1761 func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 1762 sourceVal, diags := e.Source.Value(ctx) 1763 if diags.HasErrors() { 1764 // We'll evaluate our "Each" expression here just to see if it 1765 // produces any more diagnostics we can report. Since we're not 1766 // assigning a value to our AnonSymbolExpr here it will return 1767 // DynamicVal, which should short-circuit any use of it. 1768 _, itemDiags := e.Item.Value(ctx) 1769 diags = append(diags, itemDiags...) 1770 return cty.DynamicVal, diags 1771 } 1772 1773 sourceTy := sourceVal.Type() 1774 1775 // A "special power" of splat expressions is that they can be applied 1776 // both to tuples/lists and to other values, and in the latter case 1777 // the value will be treated as an implicit single-item tuple, or as 1778 // an empty tuple if the value is null. 1779 autoUpgrade := !(sourceTy.IsTupleType() || sourceTy.IsListType() || sourceTy.IsSetType()) 1780 1781 if sourceVal.IsNull() { 1782 if autoUpgrade { 1783 return cty.EmptyTupleVal, diags 1784 } 1785 diags = append(diags, &hcl.Diagnostic{ 1786 Severity: hcl.DiagError, 1787 Summary: "Splat of null value", 1788 Detail: "Splat expressions (with the * symbol) cannot be applied to null sequences.", 1789 Subject: e.Source.Range().Ptr(), 1790 Context: hcl.RangeBetween(e.Source.Range(), e.MarkerRange).Ptr(), 1791 Expression: e.Source, 1792 EvalContext: ctx, 1793 }) 1794 return cty.DynamicVal, diags 1795 } 1796 1797 if sourceTy == cty.DynamicPseudoType { 1798 // If we don't even know the _type_ of our source value yet then 1799 // we'll need to defer all processing, since we can't decide our 1800 // result type either. 1801 return cty.DynamicVal, diags 1802 } 1803 1804 upgradedUnknown := false 1805 if autoUpgrade { 1806 // If we're upgrading an unknown value to a tuple/list, the result 1807 // cannot be known. Otherwise a tuple containing an unknown value will 1808 // upgrade to a different number of elements depending on whether 1809 // sourceVal becomes null or not. 1810 // We record this condition here so we can process any remaining 1811 // expression after the * to verify the result of the traversal. For 1812 // example, it is valid to use a splat on a single object to retrieve a 1813 // list of a single attribute, but we still need to check if that 1814 // attribute actually exists. 1815 if !sourceVal.IsKnown() { 1816 sourceRng := sourceVal.Range() 1817 if sourceRng.CouldBeNull() { 1818 upgradedUnknown = true 1819 } 1820 } 1821 1822 sourceVal = cty.TupleVal([]cty.Value{sourceVal}) 1823 sourceTy = sourceVal.Type() 1824 } 1825 1826 // We'll compute our result type lazily if we need it. In the normal case 1827 // it's inferred automatically from the value we construct. 1828 resultTy := func() (cty.Type, hcl.Diagnostics) { 1829 chiCtx := ctx.NewChild() 1830 var diags hcl.Diagnostics 1831 switch { 1832 case sourceTy.IsListType() || sourceTy.IsSetType(): 1833 ety := sourceTy.ElementType() 1834 e.Item.setValue(chiCtx, cty.UnknownVal(ety)) 1835 val, itemDiags := e.Each.Value(chiCtx) 1836 diags = append(diags, itemDiags...) 1837 e.Item.clearValue(chiCtx) // clean up our temporary value 1838 return cty.List(val.Type()), diags 1839 case sourceTy.IsTupleType(): 1840 etys := sourceTy.TupleElementTypes() 1841 resultTys := make([]cty.Type, 0, len(etys)) 1842 for _, ety := range etys { 1843 e.Item.setValue(chiCtx, cty.UnknownVal(ety)) 1844 val, itemDiags := e.Each.Value(chiCtx) 1845 diags = append(diags, itemDiags...) 1846 e.Item.clearValue(chiCtx) // clean up our temporary value 1847 resultTys = append(resultTys, val.Type()) 1848 } 1849 return cty.Tuple(resultTys), diags 1850 default: 1851 // Should never happen because of our promotion to list above. 1852 return cty.DynamicPseudoType, diags 1853 } 1854 } 1855 1856 if !sourceVal.IsKnown() { 1857 // We can't produce a known result in this case, but we'll still 1858 // indicate what the result type would be, allowing any downstream type 1859 // checking to proceed. 1860 ty, tyDiags := resultTy() 1861 diags = append(diags, tyDiags...) 1862 ret := cty.UnknownVal(ty) 1863 if ty != cty.DynamicPseudoType { 1864 ret = ret.RefineNotNull() 1865 } 1866 if ty.IsListType() && sourceVal.Type().IsCollectionType() { 1867 // We can refine the length of an unknown list result based on 1868 // the source collection's own length. 1869 sv, _ := sourceVal.Unmark() 1870 sourceRng := sv.Range() 1871 ret = ret.Refine(). 1872 CollectionLengthLowerBound(sourceRng.LengthLowerBound()). 1873 CollectionLengthUpperBound(sourceRng.LengthUpperBound()). 1874 NewValue() 1875 } 1876 return ret.WithSameMarks(sourceVal), diags 1877 } 1878 1879 // Unmark the collection, and save the marks to apply to the returned 1880 // collection result 1881 sourceVal, marks := sourceVal.Unmark() 1882 vals := make([]cty.Value, 0, sourceVal.LengthInt()) 1883 it := sourceVal.ElementIterator() 1884 if ctx == nil { 1885 // we need a context to use our AnonSymbolExpr, so we'll just 1886 // make an empty one here to use as a placeholder. 1887 ctx = ctx.NewChild() 1888 } 1889 isKnown := true 1890 for it.Next() { 1891 _, sourceItem := it.Element() 1892 e.Item.setValue(ctx, sourceItem) 1893 newItem, itemDiags := e.Each.Value(ctx) 1894 diags = append(diags, itemDiags...) 1895 if itemDiags.HasErrors() { 1896 isKnown = false 1897 } 1898 vals = append(vals, newItem) 1899 } 1900 e.Item.clearValue(ctx) // clean up our temporary value 1901 1902 if upgradedUnknown { 1903 return cty.DynamicVal, diags 1904 } 1905 1906 if !isKnown { 1907 // We'll ingore the resultTy diagnostics in this case since they 1908 // will just be the same errors we saw while iterating above. 1909 ty, _ := resultTy() 1910 return cty.UnknownVal(ty), diags 1911 } 1912 1913 switch { 1914 case sourceTy.IsListType() || sourceTy.IsSetType(): 1915 if len(vals) == 0 { 1916 ty, tyDiags := resultTy() 1917 diags = append(diags, tyDiags...) 1918 return cty.ListValEmpty(ty.ElementType()), diags 1919 } 1920 return cty.ListVal(vals).WithMarks(marks), diags 1921 default: 1922 return cty.TupleVal(vals).WithMarks(marks), diags 1923 } 1924 } 1925 1926 func (e *SplatExpr) walkChildNodes(w internalWalkFunc) { 1927 w(e.Source) 1928 w(e.Each) 1929 } 1930 1931 func (e *SplatExpr) Range() hcl.Range { 1932 return e.SrcRange 1933 } 1934 1935 func (e *SplatExpr) StartRange() hcl.Range { 1936 return e.MarkerRange 1937 } 1938 1939 // AnonSymbolExpr is used as a placeholder for a value in an expression that 1940 // can be applied dynamically to any value at runtime. 1941 // 1942 // This is a rather odd, synthetic expression. It is used as part of the 1943 // representation of splat expressions as a placeholder for the current item 1944 // being visited in the splat evaluation. 1945 // 1946 // AnonSymbolExpr cannot be evaluated in isolation. If its Value is called 1947 // directly then cty.DynamicVal will be returned. Instead, it is evaluated 1948 // in terms of another node (i.e. a splat expression) which temporarily 1949 // assigns it a value. 1950 type AnonSymbolExpr struct { 1951 SrcRange hcl.Range 1952 1953 // values and its associated lock are used to isolate concurrent 1954 // evaluations of a symbol from one another. It is the calling application's 1955 // responsibility to ensure that the same splat expression is not evalauted 1956 // concurrently within the _same_ EvalContext, but it is fine and safe to 1957 // do cuncurrent evaluations with distinct EvalContexts. 1958 values map[*hcl.EvalContext]cty.Value 1959 valuesLock sync.RWMutex 1960 } 1961 1962 func (e *AnonSymbolExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { 1963 if ctx == nil { 1964 return cty.DynamicVal, nil 1965 } 1966 1967 e.valuesLock.RLock() 1968 defer e.valuesLock.RUnlock() 1969 1970 val, exists := e.values[ctx] 1971 if !exists { 1972 return cty.DynamicVal, nil 1973 } 1974 return val, nil 1975 } 1976 1977 // setValue sets a temporary local value for the expression when evaluated 1978 // in the given context, which must be non-nil. 1979 func (e *AnonSymbolExpr) setValue(ctx *hcl.EvalContext, val cty.Value) { 1980 e.valuesLock.Lock() 1981 defer e.valuesLock.Unlock() 1982 1983 if e.values == nil { 1984 e.values = make(map[*hcl.EvalContext]cty.Value) 1985 } 1986 if ctx == nil { 1987 panic("can't setValue for a nil EvalContext") 1988 } 1989 e.values[ctx] = val 1990 } 1991 1992 func (e *AnonSymbolExpr) clearValue(ctx *hcl.EvalContext) { 1993 e.valuesLock.Lock() 1994 defer e.valuesLock.Unlock() 1995 1996 if e.values == nil { 1997 return 1998 } 1999 if ctx == nil { 2000 panic("can't clearValue for a nil EvalContext") 2001 } 2002 delete(e.values, ctx) 2003 } 2004 2005 func (e *AnonSymbolExpr) walkChildNodes(w internalWalkFunc) { 2006 // AnonSymbolExpr is a leaf node in the tree 2007 } 2008 2009 func (e *AnonSymbolExpr) Range() hcl.Range { 2010 return e.SrcRange 2011 } 2012 2013 func (e *AnonSymbolExpr) StartRange() hcl.Range { 2014 return e.SrcRange 2015 }