]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/expression.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / hcl2 / hcl / hclsyntax / expression.go
1 package hclsyntax
2
3 import (
4 "fmt"
5 "sync"
6
7 "github.com/hashicorp/hcl2/hcl"
8 "github.com/zclconf/go-cty/cty"
9 "github.com/zclconf/go-cty/cty/convert"
10 "github.com/zclconf/go-cty/cty/function"
11 )
12
13 // Expression is the abstract type for nodes that behave as HCL expressions.
14 type Expression interface {
15 Node
16
17 // The hcl.Expression methods are duplicated here, rather than simply
18 // embedded, because both Node and hcl.Expression have a Range method
19 // and so they conflict.
20
21 Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
22 Variables() []hcl.Traversal
23 StartRange() hcl.Range
24 }
25
26 // Assert that Expression implements hcl.Expression
27 var assertExprImplExpr hcl.Expression = Expression(nil)
28
29 // LiteralValueExpr is an expression that just always returns a given value.
30 type LiteralValueExpr struct {
31 Val cty.Value
32 SrcRange hcl.Range
33 }
34
35 func (e *LiteralValueExpr) walkChildNodes(w internalWalkFunc) {
36 // Literal values have no child nodes
37 }
38
39 func (e *LiteralValueExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
40 return e.Val, nil
41 }
42
43 func (e *LiteralValueExpr) Range() hcl.Range {
44 return e.SrcRange
45 }
46
47 func (e *LiteralValueExpr) StartRange() hcl.Range {
48 return e.SrcRange
49 }
50
51 // Implementation for hcl.AbsTraversalForExpr.
52 func (e *LiteralValueExpr) AsTraversal() hcl.Traversal {
53 // This one's a little weird: the contract for AsTraversal is to interpret
54 // an expression as if it were traversal syntax, and traversal syntax
55 // doesn't have the special keywords "null", "true", and "false" so these
56 // are expected to be treated like variables in that case.
57 // Since our parser already turned them into LiteralValueExpr by the time
58 // we get here, we need to undo this and infer the name that would've
59 // originally led to our value.
60 // We don't do anything for any other values, since they don't overlap
61 // with traversal roots.
62
63 if e.Val.IsNull() {
64 // In practice the parser only generates null values of the dynamic
65 // pseudo-type for literals, so we can safely assume that any null
66 // was orignally the keyword "null".
67 return hcl.Traversal{
68 hcl.TraverseRoot{
69 Name: "null",
70 SrcRange: e.SrcRange,
71 },
72 }
73 }
74
75 switch e.Val {
76 case cty.True:
77 return hcl.Traversal{
78 hcl.TraverseRoot{
79 Name: "true",
80 SrcRange: e.SrcRange,
81 },
82 }
83 case cty.False:
84 return hcl.Traversal{
85 hcl.TraverseRoot{
86 Name: "false",
87 SrcRange: e.SrcRange,
88 },
89 }
90 default:
91 // No traversal is possible for any other value.
92 return nil
93 }
94 }
95
96 // ScopeTraversalExpr is an Expression that retrieves a value from the scope
97 // using a traversal.
98 type ScopeTraversalExpr struct {
99 Traversal hcl.Traversal
100 SrcRange hcl.Range
101 }
102
103 func (e *ScopeTraversalExpr) walkChildNodes(w internalWalkFunc) {
104 // Scope traversals have no child nodes
105 }
106
107 func (e *ScopeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
108 val, diags := e.Traversal.TraverseAbs(ctx)
109 setDiagEvalContext(diags, e, ctx)
110 return val, diags
111 }
112
113 func (e *ScopeTraversalExpr) Range() hcl.Range {
114 return e.SrcRange
115 }
116
117 func (e *ScopeTraversalExpr) StartRange() hcl.Range {
118 return e.SrcRange
119 }
120
121 // Implementation for hcl.AbsTraversalForExpr.
122 func (e *ScopeTraversalExpr) AsTraversal() hcl.Traversal {
123 return e.Traversal
124 }
125
126 // RelativeTraversalExpr is an Expression that retrieves a value from another
127 // value using a _relative_ traversal.
128 type RelativeTraversalExpr struct {
129 Source Expression
130 Traversal hcl.Traversal
131 SrcRange hcl.Range
132 }
133
134 func (e *RelativeTraversalExpr) walkChildNodes(w internalWalkFunc) {
135 w(e.Source)
136 }
137
138 func (e *RelativeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
139 src, diags := e.Source.Value(ctx)
140 ret, travDiags := e.Traversal.TraverseRel(src)
141 setDiagEvalContext(travDiags, e, ctx)
142 diags = append(diags, travDiags...)
143 return ret, diags
144 }
145
146 func (e *RelativeTraversalExpr) Range() hcl.Range {
147 return e.SrcRange
148 }
149
150 func (e *RelativeTraversalExpr) StartRange() hcl.Range {
151 return e.SrcRange
152 }
153
154 // Implementation for hcl.AbsTraversalForExpr.
155 func (e *RelativeTraversalExpr) AsTraversal() hcl.Traversal {
156 // We can produce a traversal only if our source can.
157 st, diags := hcl.AbsTraversalForExpr(e.Source)
158 if diags.HasErrors() {
159 return nil
160 }
161
162 ret := make(hcl.Traversal, len(st)+len(e.Traversal))
163 copy(ret, st)
164 copy(ret[len(st):], e.Traversal)
165 return ret
166 }
167
168 // FunctionCallExpr is an Expression that calls a function from the EvalContext
169 // and returns its result.
170 type FunctionCallExpr struct {
171 Name string
172 Args []Expression
173
174 // If true, the final argument should be a tuple, list or set which will
175 // expand to be one argument per element.
176 ExpandFinal bool
177
178 NameRange hcl.Range
179 OpenParenRange hcl.Range
180 CloseParenRange hcl.Range
181 }
182
183 func (e *FunctionCallExpr) walkChildNodes(w internalWalkFunc) {
184 for _, arg := range e.Args {
185 w(arg)
186 }
187 }
188
189 func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
190 var diags hcl.Diagnostics
191
192 var f function.Function
193 exists := false
194 hasNonNilMap := false
195 thisCtx := ctx
196 for thisCtx != nil {
197 if thisCtx.Functions == nil {
198 thisCtx = thisCtx.Parent()
199 continue
200 }
201 hasNonNilMap = true
202 f, exists = thisCtx.Functions[e.Name]
203 if exists {
204 break
205 }
206 thisCtx = thisCtx.Parent()
207 }
208
209 if !exists {
210 if !hasNonNilMap {
211 return cty.DynamicVal, hcl.Diagnostics{
212 {
213 Severity: hcl.DiagError,
214 Summary: "Function calls not allowed",
215 Detail: "Functions may not be called here.",
216 Subject: e.Range().Ptr(),
217 Expression: e,
218 EvalContext: ctx,
219 },
220 }
221 }
222
223 avail := make([]string, 0, len(ctx.Functions))
224 for name := range ctx.Functions {
225 avail = append(avail, name)
226 }
227 suggestion := nameSuggestion(e.Name, avail)
228 if suggestion != "" {
229 suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
230 }
231
232 return cty.DynamicVal, hcl.Diagnostics{
233 {
234 Severity: hcl.DiagError,
235 Summary: "Call to unknown function",
236 Detail: fmt.Sprintf("There is no function named %q.%s", e.Name, suggestion),
237 Subject: &e.NameRange,
238 Context: e.Range().Ptr(),
239 Expression: e,
240 EvalContext: ctx,
241 },
242 }
243 }
244
245 params := f.Params()
246 varParam := f.VarParam()
247
248 args := e.Args
249 if e.ExpandFinal {
250 if len(args) < 1 {
251 // should never happen if the parser is behaving
252 panic("ExpandFinal set on function call with no arguments")
253 }
254 expandExpr := args[len(args)-1]
255 expandVal, expandDiags := expandExpr.Value(ctx)
256 diags = append(diags, expandDiags...)
257 if expandDiags.HasErrors() {
258 return cty.DynamicVal, diags
259 }
260
261 switch {
262 case expandVal.Type().IsTupleType() || expandVal.Type().IsListType() || expandVal.Type().IsSetType():
263 if expandVal.IsNull() {
264 diags = append(diags, &hcl.Diagnostic{
265 Severity: hcl.DiagError,
266 Summary: "Invalid expanding argument value",
267 Detail: "The expanding argument (indicated by ...) must not be null.",
268 Subject: expandExpr.Range().Ptr(),
269 Context: e.Range().Ptr(),
270 Expression: expandExpr,
271 EvalContext: ctx,
272 })
273 return cty.DynamicVal, diags
274 }
275 if !expandVal.IsKnown() {
276 return cty.DynamicVal, diags
277 }
278
279 newArgs := make([]Expression, 0, (len(args)-1)+expandVal.LengthInt())
280 newArgs = append(newArgs, args[:len(args)-1]...)
281 it := expandVal.ElementIterator()
282 for it.Next() {
283 _, val := it.Element()
284 newArgs = append(newArgs, &LiteralValueExpr{
285 Val: val,
286 SrcRange: expandExpr.Range(),
287 })
288 }
289 args = newArgs
290 default:
291 diags = append(diags, &hcl.Diagnostic{
292 Severity: hcl.DiagError,
293 Summary: "Invalid expanding argument value",
294 Detail: "The expanding argument (indicated by ...) must be of a tuple, list, or set type.",
295 Subject: expandExpr.Range().Ptr(),
296 Context: e.Range().Ptr(),
297 Expression: expandExpr,
298 EvalContext: ctx,
299 })
300 return cty.DynamicVal, diags
301 }
302 }
303
304 if len(args) < len(params) {
305 missing := params[len(args)]
306 qual := ""
307 if varParam != nil {
308 qual = " at least"
309 }
310 return cty.DynamicVal, hcl.Diagnostics{
311 {
312 Severity: hcl.DiagError,
313 Summary: "Not enough function arguments",
314 Detail: fmt.Sprintf(
315 "Function %q expects%s %d argument(s). Missing value for %q.",
316 e.Name, qual, len(params), missing.Name,
317 ),
318 Subject: &e.CloseParenRange,
319 Context: e.Range().Ptr(),
320 Expression: e,
321 EvalContext: ctx,
322 },
323 }
324 }
325
326 if varParam == nil && len(args) > len(params) {
327 return cty.DynamicVal, hcl.Diagnostics{
328 {
329 Severity: hcl.DiagError,
330 Summary: "Too many function arguments",
331 Detail: fmt.Sprintf(
332 "Function %q expects only %d argument(s).",
333 e.Name, len(params),
334 ),
335 Subject: args[len(params)].StartRange().Ptr(),
336 Context: e.Range().Ptr(),
337 Expression: e,
338 EvalContext: ctx,
339 },
340 }
341 }
342
343 argVals := make([]cty.Value, len(args))
344
345 for i, argExpr := range args {
346 var param *function.Parameter
347 if i < len(params) {
348 param = &params[i]
349 } else {
350 param = varParam
351 }
352
353 val, argDiags := argExpr.Value(ctx)
354 if len(argDiags) > 0 {
355 diags = append(diags, argDiags...)
356 }
357
358 // Try to convert our value to the parameter type
359 val, err := convert.Convert(val, param.Type)
360 if err != nil {
361 diags = append(diags, &hcl.Diagnostic{
362 Severity: hcl.DiagError,
363 Summary: "Invalid function argument",
364 Detail: fmt.Sprintf(
365 "Invalid value for %q parameter: %s.",
366 param.Name, err,
367 ),
368 Subject: argExpr.StartRange().Ptr(),
369 Context: e.Range().Ptr(),
370 Expression: argExpr,
371 EvalContext: ctx,
372 })
373 }
374
375 argVals[i] = val
376 }
377
378 if diags.HasErrors() {
379 // Don't try to execute the function if we already have errors with
380 // the arguments, because the result will probably be a confusing
381 // error message.
382 return cty.DynamicVal, diags
383 }
384
385 resultVal, err := f.Call(argVals)
386 if err != nil {
387 switch terr := err.(type) {
388 case function.ArgError:
389 i := terr.Index
390 var param *function.Parameter
391 if i < len(params) {
392 param = &params[i]
393 } else {
394 param = varParam
395 }
396 argExpr := e.Args[i]
397
398 // TODO: we should also unpick a PathError here and show the
399 // path to the deep value where the error was detected.
400 diags = append(diags, &hcl.Diagnostic{
401 Severity: hcl.DiagError,
402 Summary: "Invalid function argument",
403 Detail: fmt.Sprintf(
404 "Invalid value for %q parameter: %s.",
405 param.Name, err,
406 ),
407 Subject: argExpr.StartRange().Ptr(),
408 Context: e.Range().Ptr(),
409 Expression: argExpr,
410 EvalContext: ctx,
411 })
412
413 default:
414 diags = append(diags, &hcl.Diagnostic{
415 Severity: hcl.DiagError,
416 Summary: "Error in function call",
417 Detail: fmt.Sprintf(
418 "Call to function %q failed: %s.",
419 e.Name, err,
420 ),
421 Subject: e.StartRange().Ptr(),
422 Context: e.Range().Ptr(),
423 Expression: e,
424 EvalContext: ctx,
425 })
426 }
427
428 return cty.DynamicVal, diags
429 }
430
431 return resultVal, diags
432 }
433
434 func (e *FunctionCallExpr) Range() hcl.Range {
435 return hcl.RangeBetween(e.NameRange, e.CloseParenRange)
436 }
437
438 func (e *FunctionCallExpr) StartRange() hcl.Range {
439 return hcl.RangeBetween(e.NameRange, e.OpenParenRange)
440 }
441
442 // Implementation for hcl.ExprCall.
443 func (e *FunctionCallExpr) ExprCall() *hcl.StaticCall {
444 ret := &hcl.StaticCall{
445 Name: e.Name,
446 NameRange: e.NameRange,
447 Arguments: make([]hcl.Expression, len(e.Args)),
448 ArgsRange: hcl.RangeBetween(e.OpenParenRange, e.CloseParenRange),
449 }
450 // Need to convert our own Expression objects into hcl.Expression.
451 for i, arg := range e.Args {
452 ret.Arguments[i] = arg
453 }
454 return ret
455 }
456
457 type ConditionalExpr struct {
458 Condition Expression
459 TrueResult Expression
460 FalseResult Expression
461
462 SrcRange hcl.Range
463 }
464
465 func (e *ConditionalExpr) walkChildNodes(w internalWalkFunc) {
466 w(e.Condition)
467 w(e.TrueResult)
468 w(e.FalseResult)
469 }
470
471 func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
472 trueResult, trueDiags := e.TrueResult.Value(ctx)
473 falseResult, falseDiags := e.FalseResult.Value(ctx)
474 var diags hcl.Diagnostics
475
476 // Try to find a type that both results can be converted to.
477 resultType, convs := convert.UnifyUnsafe([]cty.Type{trueResult.Type(), falseResult.Type()})
478 if resultType == cty.NilType {
479 return cty.DynamicVal, hcl.Diagnostics{
480 {
481 Severity: hcl.DiagError,
482 Summary: "Inconsistent conditional result types",
483 Detail: fmt.Sprintf(
484 // FIXME: Need a helper function for showing natural-language type diffs,
485 // since this will generate some useless messages in some cases, like
486 // "These expressions are object and object respectively" if the
487 // object types don't exactly match.
488 "The true and false result expressions must have consistent types. The given expressions are %s and %s, respectively.",
489 trueResult.Type().FriendlyName(), falseResult.Type().FriendlyName(),
490 ),
491 Subject: hcl.RangeBetween(e.TrueResult.Range(), e.FalseResult.Range()).Ptr(),
492 Context: &e.SrcRange,
493 Expression: e,
494 EvalContext: ctx,
495 },
496 }
497 }
498
499 condResult, condDiags := e.Condition.Value(ctx)
500 diags = append(diags, condDiags...)
501 if condResult.IsNull() {
502 diags = append(diags, &hcl.Diagnostic{
503 Severity: hcl.DiagError,
504 Summary: "Null condition",
505 Detail: "The condition value is null. Conditions must either be true or false.",
506 Subject: e.Condition.Range().Ptr(),
507 Context: &e.SrcRange,
508 Expression: e.Condition,
509 EvalContext: ctx,
510 })
511 return cty.UnknownVal(resultType), diags
512 }
513 if !condResult.IsKnown() {
514 return cty.UnknownVal(resultType), diags
515 }
516 condResult, err := convert.Convert(condResult, cty.Bool)
517 if err != nil {
518 diags = append(diags, &hcl.Diagnostic{
519 Severity: hcl.DiagError,
520 Summary: "Incorrect condition type",
521 Detail: fmt.Sprintf("The condition expression must be of type bool."),
522 Subject: e.Condition.Range().Ptr(),
523 Context: &e.SrcRange,
524 Expression: e.Condition,
525 EvalContext: ctx,
526 })
527 return cty.UnknownVal(resultType), diags
528 }
529
530 if condResult.True() {
531 diags = append(diags, trueDiags...)
532 if convs[0] != nil {
533 var err error
534 trueResult, err = convs[0](trueResult)
535 if err != nil {
536 // Unsafe conversion failed with the concrete result value
537 diags = append(diags, &hcl.Diagnostic{
538 Severity: hcl.DiagError,
539 Summary: "Inconsistent conditional result types",
540 Detail: fmt.Sprintf(
541 "The true result value has the wrong type: %s.",
542 err.Error(),
543 ),
544 Subject: e.TrueResult.Range().Ptr(),
545 Context: &e.SrcRange,
546 Expression: e.TrueResult,
547 EvalContext: ctx,
548 })
549 trueResult = cty.UnknownVal(resultType)
550 }
551 }
552 return trueResult, diags
553 } else {
554 diags = append(diags, falseDiags...)
555 if convs[1] != nil {
556 var err error
557 falseResult, err = convs[1](falseResult)
558 if err != nil {
559 // Unsafe conversion failed with the concrete result value
560 diags = append(diags, &hcl.Diagnostic{
561 Severity: hcl.DiagError,
562 Summary: "Inconsistent conditional result types",
563 Detail: fmt.Sprintf(
564 "The false result value has the wrong type: %s.",
565 err.Error(),
566 ),
567 Subject: e.FalseResult.Range().Ptr(),
568 Context: &e.SrcRange,
569 Expression: e.FalseResult,
570 EvalContext: ctx,
571 })
572 falseResult = cty.UnknownVal(resultType)
573 }
574 }
575 return falseResult, diags
576 }
577 }
578
579 func (e *ConditionalExpr) Range() hcl.Range {
580 return e.SrcRange
581 }
582
583 func (e *ConditionalExpr) StartRange() hcl.Range {
584 return e.Condition.StartRange()
585 }
586
587 type IndexExpr struct {
588 Collection Expression
589 Key Expression
590
591 SrcRange hcl.Range
592 OpenRange hcl.Range
593 }
594
595 func (e *IndexExpr) walkChildNodes(w internalWalkFunc) {
596 w(e.Collection)
597 w(e.Key)
598 }
599
600 func (e *IndexExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
601 var diags hcl.Diagnostics
602 coll, collDiags := e.Collection.Value(ctx)
603 key, keyDiags := e.Key.Value(ctx)
604 diags = append(diags, collDiags...)
605 diags = append(diags, keyDiags...)
606
607 val, indexDiags := hcl.Index(coll, key, &e.SrcRange)
608 setDiagEvalContext(indexDiags, e, ctx)
609 diags = append(diags, indexDiags...)
610 return val, diags
611 }
612
613 func (e *IndexExpr) Range() hcl.Range {
614 return e.SrcRange
615 }
616
617 func (e *IndexExpr) StartRange() hcl.Range {
618 return e.OpenRange
619 }
620
621 type TupleConsExpr struct {
622 Exprs []Expression
623
624 SrcRange hcl.Range
625 OpenRange hcl.Range
626 }
627
628 func (e *TupleConsExpr) walkChildNodes(w internalWalkFunc) {
629 for _, expr := range e.Exprs {
630 w(expr)
631 }
632 }
633
634 func (e *TupleConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
635 var vals []cty.Value
636 var diags hcl.Diagnostics
637
638 vals = make([]cty.Value, len(e.Exprs))
639 for i, expr := range e.Exprs {
640 val, valDiags := expr.Value(ctx)
641 vals[i] = val
642 diags = append(diags, valDiags...)
643 }
644
645 return cty.TupleVal(vals), diags
646 }
647
648 func (e *TupleConsExpr) Range() hcl.Range {
649 return e.SrcRange
650 }
651
652 func (e *TupleConsExpr) StartRange() hcl.Range {
653 return e.OpenRange
654 }
655
656 // Implementation for hcl.ExprList
657 func (e *TupleConsExpr) ExprList() []hcl.Expression {
658 ret := make([]hcl.Expression, len(e.Exprs))
659 for i, expr := range e.Exprs {
660 ret[i] = expr
661 }
662 return ret
663 }
664
665 type ObjectConsExpr struct {
666 Items []ObjectConsItem
667
668 SrcRange hcl.Range
669 OpenRange hcl.Range
670 }
671
672 type ObjectConsItem struct {
673 KeyExpr Expression
674 ValueExpr Expression
675 }
676
677 func (e *ObjectConsExpr) walkChildNodes(w internalWalkFunc) {
678 for _, item := range e.Items {
679 w(item.KeyExpr)
680 w(item.ValueExpr)
681 }
682 }
683
684 func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
685 var vals map[string]cty.Value
686 var diags hcl.Diagnostics
687
688 // This will get set to true if we fail to produce any of our keys,
689 // either because they are actually unknown or if the evaluation produces
690 // errors. In all of these case we must return DynamicPseudoType because
691 // we're unable to know the full set of keys our object has, and thus
692 // we can't produce a complete value of the intended type.
693 //
694 // We still evaluate all of the item keys and values to make sure that we
695 // get as complete as possible a set of diagnostics.
696 known := true
697
698 vals = make(map[string]cty.Value, len(e.Items))
699 for _, item := range e.Items {
700 key, keyDiags := item.KeyExpr.Value(ctx)
701 diags = append(diags, keyDiags...)
702
703 val, valDiags := item.ValueExpr.Value(ctx)
704 diags = append(diags, valDiags...)
705
706 if keyDiags.HasErrors() {
707 known = false
708 continue
709 }
710
711 if key.IsNull() {
712 diags = append(diags, &hcl.Diagnostic{
713 Severity: hcl.DiagError,
714 Summary: "Null value as key",
715 Detail: "Can't use a null value as a key.",
716 Subject: item.ValueExpr.Range().Ptr(),
717 Expression: item.KeyExpr,
718 EvalContext: ctx,
719 })
720 known = false
721 continue
722 }
723
724 var err error
725 key, err = convert.Convert(key, cty.String)
726 if err != nil {
727 diags = append(diags, &hcl.Diagnostic{
728 Severity: hcl.DiagError,
729 Summary: "Incorrect key type",
730 Detail: fmt.Sprintf("Can't use this value as a key: %s.", err.Error()),
731 Subject: item.KeyExpr.Range().Ptr(),
732 Expression: item.KeyExpr,
733 EvalContext: ctx,
734 })
735 known = false
736 continue
737 }
738
739 if !key.IsKnown() {
740 known = false
741 continue
742 }
743
744 keyStr := key.AsString()
745
746 vals[keyStr] = val
747 }
748
749 if !known {
750 return cty.DynamicVal, diags
751 }
752
753 return cty.ObjectVal(vals), diags
754 }
755
756 func (e *ObjectConsExpr) Range() hcl.Range {
757 return e.SrcRange
758 }
759
760 func (e *ObjectConsExpr) StartRange() hcl.Range {
761 return e.OpenRange
762 }
763
764 // Implementation for hcl.ExprMap
765 func (e *ObjectConsExpr) ExprMap() []hcl.KeyValuePair {
766 ret := make([]hcl.KeyValuePair, len(e.Items))
767 for i, item := range e.Items {
768 ret[i] = hcl.KeyValuePair{
769 Key: item.KeyExpr,
770 Value: item.ValueExpr,
771 }
772 }
773 return ret
774 }
775
776 // ObjectConsKeyExpr is a special wrapper used only for ObjectConsExpr keys,
777 // which deals with the special case that a naked identifier in that position
778 // must be interpreted as a literal string rather than evaluated directly.
779 type ObjectConsKeyExpr struct {
780 Wrapped Expression
781 }
782
783 func (e *ObjectConsKeyExpr) literalName() string {
784 // This is our logic for deciding whether to behave like a literal string.
785 // We lean on our AbsTraversalForExpr implementation here, which already
786 // deals with some awkward cases like the expression being the result
787 // of the keywords "null", "true" and "false" which we'd want to interpret
788 // as keys here too.
789 return hcl.ExprAsKeyword(e.Wrapped)
790 }
791
792 func (e *ObjectConsKeyExpr) walkChildNodes(w internalWalkFunc) {
793 // We only treat our wrapped expression as a real expression if we're
794 // not going to interpret it as a literal.
795 if e.literalName() == "" {
796 w(e.Wrapped)
797 }
798 }
799
800 func (e *ObjectConsKeyExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
801 // Because we accept a naked identifier as a literal key rather than a
802 // reference, it's confusing to accept a traversal containing periods
803 // here since we can't tell if the user intends to create a key with
804 // periods or actually reference something. To avoid confusing downstream
805 // errors we'll just prohibit a naked multi-step traversal here and
806 // require the user to state their intent more clearly.
807 // (This is handled at evaluation time rather than parse time because
808 // an application using static analysis _can_ accept a naked multi-step
809 // traversal here, if desired.)
810 if travExpr, isTraversal := e.Wrapped.(*ScopeTraversalExpr); isTraversal && len(travExpr.Traversal) > 1 {
811 var diags hcl.Diagnostics
812 diags = append(diags, &hcl.Diagnostic{
813 Severity: hcl.DiagError,
814 Summary: "Ambiguous attribute key",
815 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.",
816 Subject: e.Range().Ptr(),
817 })
818 return cty.DynamicVal, diags
819 }
820
821 if ln := e.literalName(); ln != "" {
822 return cty.StringVal(ln), nil
823 }
824 return e.Wrapped.Value(ctx)
825 }
826
827 func (e *ObjectConsKeyExpr) Range() hcl.Range {
828 return e.Wrapped.Range()
829 }
830
831 func (e *ObjectConsKeyExpr) StartRange() hcl.Range {
832 return e.Wrapped.StartRange()
833 }
834
835 // Implementation for hcl.AbsTraversalForExpr.
836 func (e *ObjectConsKeyExpr) AsTraversal() hcl.Traversal {
837 // We can produce a traversal only if our wrappee can.
838 st, diags := hcl.AbsTraversalForExpr(e.Wrapped)
839 if diags.HasErrors() {
840 return nil
841 }
842
843 return st
844 }
845
846 func (e *ObjectConsKeyExpr) UnwrapExpression() Expression {
847 return e.Wrapped
848 }
849
850 // ForExpr represents iteration constructs:
851 //
852 // tuple = [for i, v in list: upper(v) if i > 2]
853 // object = {for k, v in map: k => upper(v)}
854 // object_of_tuples = {for v in list: v.key: v...}
855 type ForExpr struct {
856 KeyVar string // empty if ignoring the key
857 ValVar string
858
859 CollExpr Expression
860
861 KeyExpr Expression // nil when producing a tuple
862 ValExpr Expression
863 CondExpr Expression // null if no "if" clause is present
864
865 Group bool // set if the ellipsis is used on the value in an object for
866
867 SrcRange hcl.Range
868 OpenRange hcl.Range
869 CloseRange hcl.Range
870 }
871
872 func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
873 var diags hcl.Diagnostics
874
875 collVal, collDiags := e.CollExpr.Value(ctx)
876 diags = append(diags, collDiags...)
877
878 if collVal.IsNull() {
879 diags = append(diags, &hcl.Diagnostic{
880 Severity: hcl.DiagError,
881 Summary: "Iteration over null value",
882 Detail: "A null value cannot be used as the collection in a 'for' expression.",
883 Subject: e.CollExpr.Range().Ptr(),
884 Context: &e.SrcRange,
885 Expression: e.CollExpr,
886 EvalContext: ctx,
887 })
888 return cty.DynamicVal, diags
889 }
890 if collVal.Type() == cty.DynamicPseudoType {
891 return cty.DynamicVal, diags
892 }
893 if !collVal.CanIterateElements() {
894 diags = append(diags, &hcl.Diagnostic{
895 Severity: hcl.DiagError,
896 Summary: "Iteration over non-iterable value",
897 Detail: fmt.Sprintf(
898 "A value of type %s cannot be used as the collection in a 'for' expression.",
899 collVal.Type().FriendlyName(),
900 ),
901 Subject: e.CollExpr.Range().Ptr(),
902 Context: &e.SrcRange,
903 Expression: e.CollExpr,
904 EvalContext: ctx,
905 })
906 return cty.DynamicVal, diags
907 }
908 if !collVal.IsKnown() {
909 return cty.DynamicVal, diags
910 }
911
912 // Before we start we'll do an early check to see if any CondExpr we've
913 // been given is of the wrong type. This isn't 100% reliable (it may
914 // be DynamicVal until real values are given) but it should catch some
915 // straightforward cases and prevent a barrage of repeated errors.
916 if e.CondExpr != nil {
917 childCtx := ctx.NewChild()
918 childCtx.Variables = map[string]cty.Value{}
919 if e.KeyVar != "" {
920 childCtx.Variables[e.KeyVar] = cty.DynamicVal
921 }
922 childCtx.Variables[e.ValVar] = cty.DynamicVal
923
924 result, condDiags := e.CondExpr.Value(childCtx)
925 diags = append(diags, condDiags...)
926 if result.IsNull() {
927 diags = append(diags, &hcl.Diagnostic{
928 Severity: hcl.DiagError,
929 Summary: "Condition is null",
930 Detail: "The value of the 'if' clause must not be null.",
931 Subject: e.CondExpr.Range().Ptr(),
932 Context: &e.SrcRange,
933 Expression: e.CondExpr,
934 EvalContext: ctx,
935 })
936 return cty.DynamicVal, diags
937 }
938 _, err := convert.Convert(result, cty.Bool)
939 if err != nil {
940 diags = append(diags, &hcl.Diagnostic{
941 Severity: hcl.DiagError,
942 Summary: "Invalid 'for' condition",
943 Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
944 Subject: e.CondExpr.Range().Ptr(),
945 Context: &e.SrcRange,
946 Expression: e.CondExpr,
947 EvalContext: ctx,
948 })
949 return cty.DynamicVal, diags
950 }
951 if condDiags.HasErrors() {
952 return cty.DynamicVal, diags
953 }
954 }
955
956 if e.KeyExpr != nil {
957 // Producing an object
958 var vals map[string]cty.Value
959 var groupVals map[string][]cty.Value
960 if e.Group {
961 groupVals = map[string][]cty.Value{}
962 } else {
963 vals = map[string]cty.Value{}
964 }
965
966 it := collVal.ElementIterator()
967
968 known := true
969 for it.Next() {
970 k, v := it.Element()
971 childCtx := ctx.NewChild()
972 childCtx.Variables = map[string]cty.Value{}
973 if e.KeyVar != "" {
974 childCtx.Variables[e.KeyVar] = k
975 }
976 childCtx.Variables[e.ValVar] = v
977
978 if e.CondExpr != nil {
979 includeRaw, condDiags := e.CondExpr.Value(childCtx)
980 diags = append(diags, condDiags...)
981 if includeRaw.IsNull() {
982 if known {
983 diags = append(diags, &hcl.Diagnostic{
984 Severity: hcl.DiagError,
985 Summary: "Invalid 'for' condition",
986 Detail: "The value of the 'if' clause must not be null.",
987 Subject: e.CondExpr.Range().Ptr(),
988 Context: &e.SrcRange,
989 Expression: e.CondExpr,
990 EvalContext: childCtx,
991 })
992 }
993 known = false
994 continue
995 }
996 include, err := convert.Convert(includeRaw, cty.Bool)
997 if err != nil {
998 if known {
999 diags = append(diags, &hcl.Diagnostic{
1000 Severity: hcl.DiagError,
1001 Summary: "Invalid 'for' condition",
1002 Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
1003 Subject: e.CondExpr.Range().Ptr(),
1004 Context: &e.SrcRange,
1005 Expression: e.CondExpr,
1006 EvalContext: childCtx,
1007 })
1008 }
1009 known = false
1010 continue
1011 }
1012 if !include.IsKnown() {
1013 known = false
1014 continue
1015 }
1016
1017 if include.False() {
1018 // Skip this element
1019 continue
1020 }
1021 }
1022
1023 keyRaw, keyDiags := e.KeyExpr.Value(childCtx)
1024 diags = append(diags, keyDiags...)
1025 if keyRaw.IsNull() {
1026 if known {
1027 diags = append(diags, &hcl.Diagnostic{
1028 Severity: hcl.DiagError,
1029 Summary: "Invalid object key",
1030 Detail: "Key expression in 'for' expression must not produce a null value.",
1031 Subject: e.KeyExpr.Range().Ptr(),
1032 Context: &e.SrcRange,
1033 Expression: e.KeyExpr,
1034 EvalContext: childCtx,
1035 })
1036 }
1037 known = false
1038 continue
1039 }
1040 if !keyRaw.IsKnown() {
1041 known = false
1042 continue
1043 }
1044
1045 key, err := convert.Convert(keyRaw, cty.String)
1046 if err != nil {
1047 if known {
1048 diags = append(diags, &hcl.Diagnostic{
1049 Severity: hcl.DiagError,
1050 Summary: "Invalid object key",
1051 Detail: fmt.Sprintf("The key expression produced an invalid result: %s.", err.Error()),
1052 Subject: e.KeyExpr.Range().Ptr(),
1053 Context: &e.SrcRange,
1054 Expression: e.KeyExpr,
1055 EvalContext: childCtx,
1056 })
1057 }
1058 known = false
1059 continue
1060 }
1061
1062 val, valDiags := e.ValExpr.Value(childCtx)
1063 diags = append(diags, valDiags...)
1064
1065 if e.Group {
1066 k := key.AsString()
1067 groupVals[k] = append(groupVals[k], val)
1068 } else {
1069 k := key.AsString()
1070 if _, exists := vals[k]; exists {
1071 diags = append(diags, &hcl.Diagnostic{
1072 Severity: hcl.DiagError,
1073 Summary: "Duplicate object key",
1074 Detail: fmt.Sprintf(
1075 "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.",
1076 k,
1077 ),
1078 Subject: e.KeyExpr.Range().Ptr(),
1079 Context: &e.SrcRange,
1080 Expression: e.KeyExpr,
1081 EvalContext: childCtx,
1082 })
1083 } else {
1084 vals[key.AsString()] = val
1085 }
1086 }
1087 }
1088
1089 if !known {
1090 return cty.DynamicVal, diags
1091 }
1092
1093 if e.Group {
1094 vals = map[string]cty.Value{}
1095 for k, gvs := range groupVals {
1096 vals[k] = cty.TupleVal(gvs)
1097 }
1098 }
1099
1100 return cty.ObjectVal(vals), diags
1101
1102 } else {
1103 // Producing a tuple
1104 vals := []cty.Value{}
1105
1106 it := collVal.ElementIterator()
1107
1108 known := true
1109 for it.Next() {
1110 k, v := it.Element()
1111 childCtx := ctx.NewChild()
1112 childCtx.Variables = map[string]cty.Value{}
1113 if e.KeyVar != "" {
1114 childCtx.Variables[e.KeyVar] = k
1115 }
1116 childCtx.Variables[e.ValVar] = v
1117
1118 if e.CondExpr != nil {
1119 includeRaw, condDiags := e.CondExpr.Value(childCtx)
1120 diags = append(diags, condDiags...)
1121 if includeRaw.IsNull() {
1122 if known {
1123 diags = append(diags, &hcl.Diagnostic{
1124 Severity: hcl.DiagError,
1125 Summary: "Invalid 'for' condition",
1126 Detail: "The value of the 'if' clause must not be null.",
1127 Subject: e.CondExpr.Range().Ptr(),
1128 Context: &e.SrcRange,
1129 Expression: e.CondExpr,
1130 EvalContext: childCtx,
1131 })
1132 }
1133 known = false
1134 continue
1135 }
1136 if !includeRaw.IsKnown() {
1137 // We will eventually return DynamicVal, but we'll continue
1138 // iterating in case there are other diagnostics to gather
1139 // for later elements.
1140 known = false
1141 continue
1142 }
1143
1144 include, err := convert.Convert(includeRaw, cty.Bool)
1145 if err != nil {
1146 if known {
1147 diags = append(diags, &hcl.Diagnostic{
1148 Severity: hcl.DiagError,
1149 Summary: "Invalid 'for' condition",
1150 Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
1151 Subject: e.CondExpr.Range().Ptr(),
1152 Context: &e.SrcRange,
1153 Expression: e.CondExpr,
1154 EvalContext: childCtx,
1155 })
1156 }
1157 known = false
1158 continue
1159 }
1160
1161 if include.False() {
1162 // Skip this element
1163 continue
1164 }
1165 }
1166
1167 val, valDiags := e.ValExpr.Value(childCtx)
1168 diags = append(diags, valDiags...)
1169 vals = append(vals, val)
1170 }
1171
1172 if !known {
1173 return cty.DynamicVal, diags
1174 }
1175
1176 return cty.TupleVal(vals), diags
1177 }
1178 }
1179
1180 func (e *ForExpr) walkChildNodes(w internalWalkFunc) {
1181 w(e.CollExpr)
1182
1183 scopeNames := map[string]struct{}{}
1184 if e.KeyVar != "" {
1185 scopeNames[e.KeyVar] = struct{}{}
1186 }
1187 if e.ValVar != "" {
1188 scopeNames[e.ValVar] = struct{}{}
1189 }
1190
1191 if e.KeyExpr != nil {
1192 w(ChildScope{
1193 LocalNames: scopeNames,
1194 Expr: e.KeyExpr,
1195 })
1196 }
1197 w(ChildScope{
1198 LocalNames: scopeNames,
1199 Expr: e.ValExpr,
1200 })
1201 if e.CondExpr != nil {
1202 w(ChildScope{
1203 LocalNames: scopeNames,
1204 Expr: e.CondExpr,
1205 })
1206 }
1207 }
1208
1209 func (e *ForExpr) Range() hcl.Range {
1210 return e.SrcRange
1211 }
1212
1213 func (e *ForExpr) StartRange() hcl.Range {
1214 return e.OpenRange
1215 }
1216
1217 type SplatExpr struct {
1218 Source Expression
1219 Each Expression
1220 Item *AnonSymbolExpr
1221
1222 SrcRange hcl.Range
1223 MarkerRange hcl.Range
1224 }
1225
1226 func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1227 sourceVal, diags := e.Source.Value(ctx)
1228 if diags.HasErrors() {
1229 // We'll evaluate our "Each" expression here just to see if it
1230 // produces any more diagnostics we can report. Since we're not
1231 // assigning a value to our AnonSymbolExpr here it will return
1232 // DynamicVal, which should short-circuit any use of it.
1233 _, itemDiags := e.Item.Value(ctx)
1234 diags = append(diags, itemDiags...)
1235 return cty.DynamicVal, diags
1236 }
1237
1238 sourceTy := sourceVal.Type()
1239 if sourceTy == cty.DynamicPseudoType {
1240 // If we don't even know the _type_ of our source value yet then
1241 // we'll need to defer all processing, since we can't decide our
1242 // result type either.
1243 return cty.DynamicVal, diags
1244 }
1245
1246 // A "special power" of splat expressions is that they can be applied
1247 // both to tuples/lists and to other values, and in the latter case
1248 // the value will be treated as an implicit single-item tuple, or as
1249 // an empty tuple if the value is null.
1250 autoUpgrade := !(sourceTy.IsTupleType() || sourceTy.IsListType() || sourceTy.IsSetType())
1251
1252 if sourceVal.IsNull() {
1253 if autoUpgrade {
1254 return cty.EmptyTupleVal, diags
1255 }
1256 diags = append(diags, &hcl.Diagnostic{
1257 Severity: hcl.DiagError,
1258 Summary: "Splat of null value",
1259 Detail: "Splat expressions (with the * symbol) cannot be applied to null sequences.",
1260 Subject: e.Source.Range().Ptr(),
1261 Context: hcl.RangeBetween(e.Source.Range(), e.MarkerRange).Ptr(),
1262 Expression: e.Source,
1263 EvalContext: ctx,
1264 })
1265 return cty.DynamicVal, diags
1266 }
1267
1268 if autoUpgrade {
1269 sourceVal = cty.TupleVal([]cty.Value{sourceVal})
1270 sourceTy = sourceVal.Type()
1271 }
1272
1273 // We'll compute our result type lazily if we need it. In the normal case
1274 // it's inferred automatically from the value we construct.
1275 resultTy := func() (cty.Type, hcl.Diagnostics) {
1276 chiCtx := ctx.NewChild()
1277 var diags hcl.Diagnostics
1278 switch {
1279 case sourceTy.IsListType() || sourceTy.IsSetType():
1280 ety := sourceTy.ElementType()
1281 e.Item.setValue(chiCtx, cty.UnknownVal(ety))
1282 val, itemDiags := e.Each.Value(chiCtx)
1283 diags = append(diags, itemDiags...)
1284 e.Item.clearValue(chiCtx) // clean up our temporary value
1285 return cty.List(val.Type()), diags
1286 case sourceTy.IsTupleType():
1287 etys := sourceTy.TupleElementTypes()
1288 resultTys := make([]cty.Type, 0, len(etys))
1289 for _, ety := range etys {
1290 e.Item.setValue(chiCtx, cty.UnknownVal(ety))
1291 val, itemDiags := e.Each.Value(chiCtx)
1292 diags = append(diags, itemDiags...)
1293 e.Item.clearValue(chiCtx) // clean up our temporary value
1294 resultTys = append(resultTys, val.Type())
1295 }
1296 return cty.Tuple(resultTys), diags
1297 default:
1298 // Should never happen because of our promotion to list above.
1299 return cty.DynamicPseudoType, diags
1300 }
1301 }
1302
1303 if !sourceVal.IsKnown() {
1304 // We can't produce a known result in this case, but we'll still
1305 // indicate what the result type would be, allowing any downstream type
1306 // checking to proceed.
1307 ty, tyDiags := resultTy()
1308 diags = append(diags, tyDiags...)
1309 return cty.UnknownVal(ty), diags
1310 }
1311
1312 vals := make([]cty.Value, 0, sourceVal.LengthInt())
1313 it := sourceVal.ElementIterator()
1314 if ctx == nil {
1315 // we need a context to use our AnonSymbolExpr, so we'll just
1316 // make an empty one here to use as a placeholder.
1317 ctx = ctx.NewChild()
1318 }
1319 isKnown := true
1320 for it.Next() {
1321 _, sourceItem := it.Element()
1322 e.Item.setValue(ctx, sourceItem)
1323 newItem, itemDiags := e.Each.Value(ctx)
1324 diags = append(diags, itemDiags...)
1325 if itemDiags.HasErrors() {
1326 isKnown = false
1327 }
1328 vals = append(vals, newItem)
1329 }
1330 e.Item.clearValue(ctx) // clean up our temporary value
1331
1332 if !isKnown {
1333 // We'll ingore the resultTy diagnostics in this case since they
1334 // will just be the same errors we saw while iterating above.
1335 ty, _ := resultTy()
1336 return cty.UnknownVal(ty), diags
1337 }
1338
1339 switch {
1340 case sourceTy.IsListType() || sourceTy.IsSetType():
1341 if len(vals) == 0 {
1342 ty, tyDiags := resultTy()
1343 diags = append(diags, tyDiags...)
1344 return cty.ListValEmpty(ty.ElementType()), diags
1345 }
1346 return cty.ListVal(vals), diags
1347 default:
1348 return cty.TupleVal(vals), diags
1349 }
1350 }
1351
1352 func (e *SplatExpr) walkChildNodes(w internalWalkFunc) {
1353 w(e.Source)
1354 w(e.Each)
1355 }
1356
1357 func (e *SplatExpr) Range() hcl.Range {
1358 return e.SrcRange
1359 }
1360
1361 func (e *SplatExpr) StartRange() hcl.Range {
1362 return e.MarkerRange
1363 }
1364
1365 // AnonSymbolExpr is used as a placeholder for a value in an expression that
1366 // can be applied dynamically to any value at runtime.
1367 //
1368 // This is a rather odd, synthetic expression. It is used as part of the
1369 // representation of splat expressions as a placeholder for the current item
1370 // being visited in the splat evaluation.
1371 //
1372 // AnonSymbolExpr cannot be evaluated in isolation. If its Value is called
1373 // directly then cty.DynamicVal will be returned. Instead, it is evaluated
1374 // in terms of another node (i.e. a splat expression) which temporarily
1375 // assigns it a value.
1376 type AnonSymbolExpr struct {
1377 SrcRange hcl.Range
1378
1379 // values and its associated lock are used to isolate concurrent
1380 // evaluations of a symbol from one another. It is the calling application's
1381 // responsibility to ensure that the same splat expression is not evalauted
1382 // concurrently within the _same_ EvalContext, but it is fine and safe to
1383 // do cuncurrent evaluations with distinct EvalContexts.
1384 values map[*hcl.EvalContext]cty.Value
1385 valuesLock sync.RWMutex
1386 }
1387
1388 func (e *AnonSymbolExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1389 if ctx == nil {
1390 return cty.DynamicVal, nil
1391 }
1392
1393 e.valuesLock.RLock()
1394 defer e.valuesLock.RUnlock()
1395
1396 val, exists := e.values[ctx]
1397 if !exists {
1398 return cty.DynamicVal, nil
1399 }
1400 return val, nil
1401 }
1402
1403 // setValue sets a temporary local value for the expression when evaluated
1404 // in the given context, which must be non-nil.
1405 func (e *AnonSymbolExpr) setValue(ctx *hcl.EvalContext, val cty.Value) {
1406 e.valuesLock.Lock()
1407 defer e.valuesLock.Unlock()
1408
1409 if e.values == nil {
1410 e.values = make(map[*hcl.EvalContext]cty.Value)
1411 }
1412 if ctx == nil {
1413 panic("can't setValue for a nil EvalContext")
1414 }
1415 e.values[ctx] = val
1416 }
1417
1418 func (e *AnonSymbolExpr) clearValue(ctx *hcl.EvalContext) {
1419 e.valuesLock.Lock()
1420 defer e.valuesLock.Unlock()
1421
1422 if e.values == nil {
1423 return
1424 }
1425 if ctx == nil {
1426 panic("can't clearValue for a nil EvalContext")
1427 }
1428 delete(e.values, ctx)
1429 }
1430
1431 func (e *AnonSymbolExpr) walkChildNodes(w internalWalkFunc) {
1432 // AnonSymbolExpr is a leaf node in the tree
1433 }
1434
1435 func (e *AnonSymbolExpr) Range() hcl.Range {
1436 return e.SrcRange
1437 }
1438
1439 func (e *AnonSymbolExpr) StartRange() hcl.Range {
1440 return e.SrcRange
1441 }