1package hclsyntax
2
3import (
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.
14type 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
27var assertExprImplExpr hcl.Expression = Expression(nil)
28
29// LiteralValueExpr is an expression that just always returns a given value.
30type LiteralValueExpr struct {
31	Val      cty.Value
32	SrcRange hcl.Range
33}
34
35func (e *LiteralValueExpr) walkChildNodes(w internalWalkFunc) {
36	// Literal values have no child nodes
37}
38
39func (e *LiteralValueExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
40	return e.Val, nil
41}
42
43func (e *LiteralValueExpr) Range() hcl.Range {
44	return e.SrcRange
45}
46
47func (e *LiteralValueExpr) StartRange() hcl.Range {
48	return e.SrcRange
49}
50
51// Implementation for hcl.AbsTraversalForExpr.
52func (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.
98type ScopeTraversalExpr struct {
99	Traversal hcl.Traversal
100	SrcRange  hcl.Range
101}
102
103func (e *ScopeTraversalExpr) walkChildNodes(w internalWalkFunc) {
104	// Scope traversals have no child nodes
105}
106
107func (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
113func (e *ScopeTraversalExpr) Range() hcl.Range {
114	return e.SrcRange
115}
116
117func (e *ScopeTraversalExpr) StartRange() hcl.Range {
118	return e.SrcRange
119}
120
121// Implementation for hcl.AbsTraversalForExpr.
122func (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.
128type RelativeTraversalExpr struct {
129	Source    Expression
130	Traversal hcl.Traversal
131	SrcRange  hcl.Range
132}
133
134func (e *RelativeTraversalExpr) walkChildNodes(w internalWalkFunc) {
135	w(e.Source)
136}
137
138func (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
146func (e *RelativeTraversalExpr) Range() hcl.Range {
147	return e.SrcRange
148}
149
150func (e *RelativeTraversalExpr) StartRange() hcl.Range {
151	return e.SrcRange
152}
153
154// Implementation for hcl.AbsTraversalForExpr.
155func (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.
170type 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
183func (e *FunctionCallExpr) walkChildNodes(w internalWalkFunc) {
184	for _, arg := range e.Args {
185		w(arg)
186	}
187}
188
189func (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
434func (e *FunctionCallExpr) Range() hcl.Range {
435	return hcl.RangeBetween(e.NameRange, e.CloseParenRange)
436}
437
438func (e *FunctionCallExpr) StartRange() hcl.Range {
439	return hcl.RangeBetween(e.NameRange, e.OpenParenRange)
440}
441
442// Implementation for hcl.ExprCall.
443func (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
457type ConditionalExpr struct {
458	Condition   Expression
459	TrueResult  Expression
460	FalseResult Expression
461
462	SrcRange hcl.Range
463}
464
465func (e *ConditionalExpr) walkChildNodes(w internalWalkFunc) {
466	w(e.Condition)
467	w(e.TrueResult)
468	w(e.FalseResult)
469}
470
471func (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	resultType := cty.DynamicPseudoType
477	convs := make([]convert.Conversion, 2)
478
479	switch {
480	// If either case is a dynamic null value (which would result from a
481	// literal null in the config), we know that it can convert to the expected
482	// type of the opposite case, and we don't need to speculatively reduce the
483	// final result type to DynamicPseudoType.
484
485	// If we know that either Type is a DynamicPseudoType, we can be certain
486	// that the other value can convert since it's a pass-through, and we don't
487	// need to unify the types. If the final evaluation results in the dynamic
488	// value being returned, there's no conversion we can do, so we return the
489	// value directly.
490	case trueResult.RawEquals(cty.NullVal(cty.DynamicPseudoType)):
491		resultType = falseResult.Type()
492		convs[0] = convert.GetConversionUnsafe(cty.DynamicPseudoType, resultType)
493	case falseResult.RawEquals(cty.NullVal(cty.DynamicPseudoType)):
494		resultType = trueResult.Type()
495		convs[1] = convert.GetConversionUnsafe(cty.DynamicPseudoType, resultType)
496	case trueResult.Type() == cty.DynamicPseudoType, falseResult.Type() == cty.DynamicPseudoType:
497		// the final resultType type is still unknown
498		// we don't need to get the conversion, because both are a noop.
499
500	default:
501		// Try to find a type that both results can be converted to.
502		resultType, convs = convert.UnifyUnsafe([]cty.Type{trueResult.Type(), falseResult.Type()})
503	}
504
505	if resultType == cty.NilType {
506		return cty.DynamicVal, hcl.Diagnostics{
507			{
508				Severity: hcl.DiagError,
509				Summary:  "Inconsistent conditional result types",
510				Detail: fmt.Sprintf(
511					// FIXME: Need a helper function for showing natural-language type diffs,
512					// since this will generate some useless messages in some cases, like
513					// "These expressions are object and object respectively" if the
514					// object types don't exactly match.
515					"The true and false result expressions must have consistent types. The given expressions are %s and %s, respectively.",
516					trueResult.Type().FriendlyName(), falseResult.Type().FriendlyName(),
517				),
518				Subject:     hcl.RangeBetween(e.TrueResult.Range(), e.FalseResult.Range()).Ptr(),
519				Context:     &e.SrcRange,
520				Expression:  e,
521				EvalContext: ctx,
522			},
523		}
524	}
525
526	condResult, condDiags := e.Condition.Value(ctx)
527	diags = append(diags, condDiags...)
528	if condResult.IsNull() {
529		diags = append(diags, &hcl.Diagnostic{
530			Severity:    hcl.DiagError,
531			Summary:     "Null condition",
532			Detail:      "The condition value is null. Conditions must either be true or false.",
533			Subject:     e.Condition.Range().Ptr(),
534			Context:     &e.SrcRange,
535			Expression:  e.Condition,
536			EvalContext: ctx,
537		})
538		return cty.UnknownVal(resultType), diags
539	}
540	if !condResult.IsKnown() {
541		return cty.UnknownVal(resultType), diags
542	}
543	condResult, err := convert.Convert(condResult, cty.Bool)
544	if err != nil {
545		diags = append(diags, &hcl.Diagnostic{
546			Severity:    hcl.DiagError,
547			Summary:     "Incorrect condition type",
548			Detail:      fmt.Sprintf("The condition expression must be of type bool."),
549			Subject:     e.Condition.Range().Ptr(),
550			Context:     &e.SrcRange,
551			Expression:  e.Condition,
552			EvalContext: ctx,
553		})
554		return cty.UnknownVal(resultType), diags
555	}
556
557	if condResult.True() {
558		diags = append(diags, trueDiags...)
559		if convs[0] != nil {
560			var err error
561			trueResult, err = convs[0](trueResult)
562			if err != nil {
563				// Unsafe conversion failed with the concrete result value
564				diags = append(diags, &hcl.Diagnostic{
565					Severity: hcl.DiagError,
566					Summary:  "Inconsistent conditional result types",
567					Detail: fmt.Sprintf(
568						"The true result value has the wrong type: %s.",
569						err.Error(),
570					),
571					Subject:     e.TrueResult.Range().Ptr(),
572					Context:     &e.SrcRange,
573					Expression:  e.TrueResult,
574					EvalContext: ctx,
575				})
576				trueResult = cty.UnknownVal(resultType)
577			}
578		}
579		return trueResult, diags
580	} else {
581		diags = append(diags, falseDiags...)
582		if convs[1] != nil {
583			var err error
584			falseResult, err = convs[1](falseResult)
585			if err != nil {
586				// Unsafe conversion failed with the concrete result value
587				diags = append(diags, &hcl.Diagnostic{
588					Severity: hcl.DiagError,
589					Summary:  "Inconsistent conditional result types",
590					Detail: fmt.Sprintf(
591						"The false result value has the wrong type: %s.",
592						err.Error(),
593					),
594					Subject:     e.FalseResult.Range().Ptr(),
595					Context:     &e.SrcRange,
596					Expression:  e.FalseResult,
597					EvalContext: ctx,
598				})
599				falseResult = cty.UnknownVal(resultType)
600			}
601		}
602		return falseResult, diags
603	}
604}
605
606func (e *ConditionalExpr) Range() hcl.Range {
607	return e.SrcRange
608}
609
610func (e *ConditionalExpr) StartRange() hcl.Range {
611	return e.Condition.StartRange()
612}
613
614type IndexExpr struct {
615	Collection Expression
616	Key        Expression
617
618	SrcRange  hcl.Range
619	OpenRange hcl.Range
620}
621
622func (e *IndexExpr) walkChildNodes(w internalWalkFunc) {
623	w(e.Collection)
624	w(e.Key)
625}
626
627func (e *IndexExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
628	var diags hcl.Diagnostics
629	coll, collDiags := e.Collection.Value(ctx)
630	key, keyDiags := e.Key.Value(ctx)
631	diags = append(diags, collDiags...)
632	diags = append(diags, keyDiags...)
633
634	val, indexDiags := hcl.Index(coll, key, &e.SrcRange)
635	setDiagEvalContext(indexDiags, e, ctx)
636	diags = append(diags, indexDiags...)
637	return val, diags
638}
639
640func (e *IndexExpr) Range() hcl.Range {
641	return e.SrcRange
642}
643
644func (e *IndexExpr) StartRange() hcl.Range {
645	return e.OpenRange
646}
647
648type TupleConsExpr struct {
649	Exprs []Expression
650
651	SrcRange  hcl.Range
652	OpenRange hcl.Range
653}
654
655func (e *TupleConsExpr) walkChildNodes(w internalWalkFunc) {
656	for _, expr := range e.Exprs {
657		w(expr)
658	}
659}
660
661func (e *TupleConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
662	var vals []cty.Value
663	var diags hcl.Diagnostics
664
665	vals = make([]cty.Value, len(e.Exprs))
666	for i, expr := range e.Exprs {
667		val, valDiags := expr.Value(ctx)
668		vals[i] = val
669		diags = append(diags, valDiags...)
670	}
671
672	return cty.TupleVal(vals), diags
673}
674
675func (e *TupleConsExpr) Range() hcl.Range {
676	return e.SrcRange
677}
678
679func (e *TupleConsExpr) StartRange() hcl.Range {
680	return e.OpenRange
681}
682
683// Implementation for hcl.ExprList
684func (e *TupleConsExpr) ExprList() []hcl.Expression {
685	ret := make([]hcl.Expression, len(e.Exprs))
686	for i, expr := range e.Exprs {
687		ret[i] = expr
688	}
689	return ret
690}
691
692type ObjectConsExpr struct {
693	Items []ObjectConsItem
694
695	SrcRange  hcl.Range
696	OpenRange hcl.Range
697}
698
699type ObjectConsItem struct {
700	KeyExpr   Expression
701	ValueExpr Expression
702}
703
704func (e *ObjectConsExpr) walkChildNodes(w internalWalkFunc) {
705	for _, item := range e.Items {
706		w(item.KeyExpr)
707		w(item.ValueExpr)
708	}
709}
710
711func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
712	var vals map[string]cty.Value
713	var diags hcl.Diagnostics
714
715	// This will get set to true if we fail to produce any of our keys,
716	// either because they are actually unknown or if the evaluation produces
717	// errors. In all of these case we must return DynamicPseudoType because
718	// we're unable to know the full set of keys our object has, and thus
719	// we can't produce a complete value of the intended type.
720	//
721	// We still evaluate all of the item keys and values to make sure that we
722	// get as complete as possible a set of diagnostics.
723	known := true
724
725	vals = make(map[string]cty.Value, len(e.Items))
726	for _, item := range e.Items {
727		key, keyDiags := item.KeyExpr.Value(ctx)
728		diags = append(diags, keyDiags...)
729
730		val, valDiags := item.ValueExpr.Value(ctx)
731		diags = append(diags, valDiags...)
732
733		if keyDiags.HasErrors() {
734			known = false
735			continue
736		}
737
738		if key.IsNull() {
739			diags = append(diags, &hcl.Diagnostic{
740				Severity:    hcl.DiagError,
741				Summary:     "Null value as key",
742				Detail:      "Can't use a null value as a key.",
743				Subject:     item.ValueExpr.Range().Ptr(),
744				Expression:  item.KeyExpr,
745				EvalContext: ctx,
746			})
747			known = false
748			continue
749		}
750
751		var err error
752		key, err = convert.Convert(key, cty.String)
753		if err != nil {
754			diags = append(diags, &hcl.Diagnostic{
755				Severity:    hcl.DiagError,
756				Summary:     "Incorrect key type",
757				Detail:      fmt.Sprintf("Can't use this value as a key: %s.", err.Error()),
758				Subject:     item.KeyExpr.Range().Ptr(),
759				Expression:  item.KeyExpr,
760				EvalContext: ctx,
761			})
762			known = false
763			continue
764		}
765
766		if !key.IsKnown() {
767			known = false
768			continue
769		}
770
771		keyStr := key.AsString()
772
773		vals[keyStr] = val
774	}
775
776	if !known {
777		return cty.DynamicVal, diags
778	}
779
780	return cty.ObjectVal(vals), diags
781}
782
783func (e *ObjectConsExpr) Range() hcl.Range {
784	return e.SrcRange
785}
786
787func (e *ObjectConsExpr) StartRange() hcl.Range {
788	return e.OpenRange
789}
790
791// Implementation for hcl.ExprMap
792func (e *ObjectConsExpr) ExprMap() []hcl.KeyValuePair {
793	ret := make([]hcl.KeyValuePair, len(e.Items))
794	for i, item := range e.Items {
795		ret[i] = hcl.KeyValuePair{
796			Key:   item.KeyExpr,
797			Value: item.ValueExpr,
798		}
799	}
800	return ret
801}
802
803// ObjectConsKeyExpr is a special wrapper used only for ObjectConsExpr keys,
804// which deals with the special case that a naked identifier in that position
805// must be interpreted as a literal string rather than evaluated directly.
806type ObjectConsKeyExpr struct {
807	Wrapped Expression
808}
809
810func (e *ObjectConsKeyExpr) literalName() string {
811	// This is our logic for deciding whether to behave like a literal string.
812	// We lean on our AbsTraversalForExpr implementation here, which already
813	// deals with some awkward cases like the expression being the result
814	// of the keywords "null", "true" and "false" which we'd want to interpret
815	// as keys here too.
816	return hcl.ExprAsKeyword(e.Wrapped)
817}
818
819func (e *ObjectConsKeyExpr) walkChildNodes(w internalWalkFunc) {
820	// We only treat our wrapped expression as a real expression if we're
821	// not going to interpret it as a literal.
822	if e.literalName() == "" {
823		w(e.Wrapped)
824	}
825}
826
827func (e *ObjectConsKeyExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
828	// Because we accept a naked identifier as a literal key rather than a
829	// reference, it's confusing to accept a traversal containing periods
830	// here since we can't tell if the user intends to create a key with
831	// periods or actually reference something. To avoid confusing downstream
832	// errors we'll just prohibit a naked multi-step traversal here and
833	// require the user to state their intent more clearly.
834	// (This is handled at evaluation time rather than parse time because
835	// an application using static analysis _can_ accept a naked multi-step
836	// traversal here, if desired.)
837	if travExpr, isTraversal := e.Wrapped.(*ScopeTraversalExpr); isTraversal && len(travExpr.Traversal) > 1 {
838		var diags hcl.Diagnostics
839		diags = append(diags, &hcl.Diagnostic{
840			Severity: hcl.DiagError,
841			Summary:  "Ambiguous attribute key",
842			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.",
843			Subject:  e.Range().Ptr(),
844		})
845		return cty.DynamicVal, diags
846	}
847
848	if ln := e.literalName(); ln != "" {
849		return cty.StringVal(ln), nil
850	}
851	return e.Wrapped.Value(ctx)
852}
853
854func (e *ObjectConsKeyExpr) Range() hcl.Range {
855	return e.Wrapped.Range()
856}
857
858func (e *ObjectConsKeyExpr) StartRange() hcl.Range {
859	return e.Wrapped.StartRange()
860}
861
862// Implementation for hcl.AbsTraversalForExpr.
863func (e *ObjectConsKeyExpr) AsTraversal() hcl.Traversal {
864	// We can produce a traversal only if our wrappee can.
865	st, diags := hcl.AbsTraversalForExpr(e.Wrapped)
866	if diags.HasErrors() {
867		return nil
868	}
869
870	return st
871}
872
873func (e *ObjectConsKeyExpr) UnwrapExpression() Expression {
874	return e.Wrapped
875}
876
877// ForExpr represents iteration constructs:
878//
879//     tuple = [for i, v in list: upper(v) if i > 2]
880//     object = {for k, v in map: k => upper(v)}
881//     object_of_tuples = {for v in list: v.key: v...}
882type ForExpr struct {
883	KeyVar string // empty if ignoring the key
884	ValVar string
885
886	CollExpr Expression
887
888	KeyExpr  Expression // nil when producing a tuple
889	ValExpr  Expression
890	CondExpr Expression // null if no "if" clause is present
891
892	Group bool // set if the ellipsis is used on the value in an object for
893
894	SrcRange   hcl.Range
895	OpenRange  hcl.Range
896	CloseRange hcl.Range
897}
898
899func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
900	var diags hcl.Diagnostics
901
902	collVal, collDiags := e.CollExpr.Value(ctx)
903	diags = append(diags, collDiags...)
904
905	if collVal.IsNull() {
906		diags = append(diags, &hcl.Diagnostic{
907			Severity:    hcl.DiagError,
908			Summary:     "Iteration over null value",
909			Detail:      "A null value cannot be used as the collection in a 'for' expression.",
910			Subject:     e.CollExpr.Range().Ptr(),
911			Context:     &e.SrcRange,
912			Expression:  e.CollExpr,
913			EvalContext: ctx,
914		})
915		return cty.DynamicVal, diags
916	}
917	if collVal.Type() == cty.DynamicPseudoType {
918		return cty.DynamicVal, diags
919	}
920	if !collVal.CanIterateElements() {
921		diags = append(diags, &hcl.Diagnostic{
922			Severity: hcl.DiagError,
923			Summary:  "Iteration over non-iterable value",
924			Detail: fmt.Sprintf(
925				"A value of type %s cannot be used as the collection in a 'for' expression.",
926				collVal.Type().FriendlyName(),
927			),
928			Subject:     e.CollExpr.Range().Ptr(),
929			Context:     &e.SrcRange,
930			Expression:  e.CollExpr,
931			EvalContext: ctx,
932		})
933		return cty.DynamicVal, diags
934	}
935	if !collVal.IsKnown() {
936		return cty.DynamicVal, diags
937	}
938
939	// Before we start we'll do an early check to see if any CondExpr we've
940	// been given is of the wrong type. This isn't 100% reliable (it may
941	// be DynamicVal until real values are given) but it should catch some
942	// straightforward cases and prevent a barrage of repeated errors.
943	if e.CondExpr != nil {
944		childCtx := ctx.NewChild()
945		childCtx.Variables = map[string]cty.Value{}
946		if e.KeyVar != "" {
947			childCtx.Variables[e.KeyVar] = cty.DynamicVal
948		}
949		childCtx.Variables[e.ValVar] = cty.DynamicVal
950
951		result, condDiags := e.CondExpr.Value(childCtx)
952		diags = append(diags, condDiags...)
953		if result.IsNull() {
954			diags = append(diags, &hcl.Diagnostic{
955				Severity:    hcl.DiagError,
956				Summary:     "Condition is null",
957				Detail:      "The value of the 'if' clause must not be null.",
958				Subject:     e.CondExpr.Range().Ptr(),
959				Context:     &e.SrcRange,
960				Expression:  e.CondExpr,
961				EvalContext: ctx,
962			})
963			return cty.DynamicVal, diags
964		}
965		_, err := convert.Convert(result, cty.Bool)
966		if err != nil {
967			diags = append(diags, &hcl.Diagnostic{
968				Severity:    hcl.DiagError,
969				Summary:     "Invalid 'for' condition",
970				Detail:      fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
971				Subject:     e.CondExpr.Range().Ptr(),
972				Context:     &e.SrcRange,
973				Expression:  e.CondExpr,
974				EvalContext: ctx,
975			})
976			return cty.DynamicVal, diags
977		}
978		if condDiags.HasErrors() {
979			return cty.DynamicVal, diags
980		}
981	}
982
983	if e.KeyExpr != nil {
984		// Producing an object
985		var vals map[string]cty.Value
986		var groupVals map[string][]cty.Value
987		if e.Group {
988			groupVals = map[string][]cty.Value{}
989		} else {
990			vals = map[string]cty.Value{}
991		}
992
993		it := collVal.ElementIterator()
994
995		known := true
996		for it.Next() {
997			k, v := it.Element()
998			childCtx := ctx.NewChild()
999			childCtx.Variables = map[string]cty.Value{}
1000			if e.KeyVar != "" {
1001				childCtx.Variables[e.KeyVar] = k
1002			}
1003			childCtx.Variables[e.ValVar] = v
1004
1005			if e.CondExpr != nil {
1006				includeRaw, condDiags := e.CondExpr.Value(childCtx)
1007				diags = append(diags, condDiags...)
1008				if includeRaw.IsNull() {
1009					if known {
1010						diags = append(diags, &hcl.Diagnostic{
1011							Severity:    hcl.DiagError,
1012							Summary:     "Invalid 'for' condition",
1013							Detail:      "The value of the 'if' clause must not be null.",
1014							Subject:     e.CondExpr.Range().Ptr(),
1015							Context:     &e.SrcRange,
1016							Expression:  e.CondExpr,
1017							EvalContext: childCtx,
1018						})
1019					}
1020					known = false
1021					continue
1022				}
1023				include, err := convert.Convert(includeRaw, cty.Bool)
1024				if err != nil {
1025					if known {
1026						diags = append(diags, &hcl.Diagnostic{
1027							Severity:    hcl.DiagError,
1028							Summary:     "Invalid 'for' condition",
1029							Detail:      fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
1030							Subject:     e.CondExpr.Range().Ptr(),
1031							Context:     &e.SrcRange,
1032							Expression:  e.CondExpr,
1033							EvalContext: childCtx,
1034						})
1035					}
1036					known = false
1037					continue
1038				}
1039				if !include.IsKnown() {
1040					known = false
1041					continue
1042				}
1043
1044				if include.False() {
1045					// Skip this element
1046					continue
1047				}
1048			}
1049
1050			keyRaw, keyDiags := e.KeyExpr.Value(childCtx)
1051			diags = append(diags, keyDiags...)
1052			if keyRaw.IsNull() {
1053				if known {
1054					diags = append(diags, &hcl.Diagnostic{
1055						Severity:    hcl.DiagError,
1056						Summary:     "Invalid object key",
1057						Detail:      "Key expression in 'for' expression must not produce a null value.",
1058						Subject:     e.KeyExpr.Range().Ptr(),
1059						Context:     &e.SrcRange,
1060						Expression:  e.KeyExpr,
1061						EvalContext: childCtx,
1062					})
1063				}
1064				known = false
1065				continue
1066			}
1067			if !keyRaw.IsKnown() {
1068				known = false
1069				continue
1070			}
1071
1072			key, err := convert.Convert(keyRaw, cty.String)
1073			if err != nil {
1074				if known {
1075					diags = append(diags, &hcl.Diagnostic{
1076						Severity:    hcl.DiagError,
1077						Summary:     "Invalid object key",
1078						Detail:      fmt.Sprintf("The key expression produced an invalid result: %s.", err.Error()),
1079						Subject:     e.KeyExpr.Range().Ptr(),
1080						Context:     &e.SrcRange,
1081						Expression:  e.KeyExpr,
1082						EvalContext: childCtx,
1083					})
1084				}
1085				known = false
1086				continue
1087			}
1088
1089			val, valDiags := e.ValExpr.Value(childCtx)
1090			diags = append(diags, valDiags...)
1091
1092			if e.Group {
1093				k := key.AsString()
1094				groupVals[k] = append(groupVals[k], val)
1095			} else {
1096				k := key.AsString()
1097				if _, exists := vals[k]; exists {
1098					diags = append(diags, &hcl.Diagnostic{
1099						Severity: hcl.DiagError,
1100						Summary:  "Duplicate object key",
1101						Detail: fmt.Sprintf(
1102							"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.",
1103							k,
1104						),
1105						Subject:     e.KeyExpr.Range().Ptr(),
1106						Context:     &e.SrcRange,
1107						Expression:  e.KeyExpr,
1108						EvalContext: childCtx,
1109					})
1110				} else {
1111					vals[key.AsString()] = val
1112				}
1113			}
1114		}
1115
1116		if !known {
1117			return cty.DynamicVal, diags
1118		}
1119
1120		if e.Group {
1121			vals = map[string]cty.Value{}
1122			for k, gvs := range groupVals {
1123				vals[k] = cty.TupleVal(gvs)
1124			}
1125		}
1126
1127		return cty.ObjectVal(vals), diags
1128
1129	} else {
1130		// Producing a tuple
1131		vals := []cty.Value{}
1132
1133		it := collVal.ElementIterator()
1134
1135		known := true
1136		for it.Next() {
1137			k, v := it.Element()
1138			childCtx := ctx.NewChild()
1139			childCtx.Variables = map[string]cty.Value{}
1140			if e.KeyVar != "" {
1141				childCtx.Variables[e.KeyVar] = k
1142			}
1143			childCtx.Variables[e.ValVar] = v
1144
1145			if e.CondExpr != nil {
1146				includeRaw, condDiags := e.CondExpr.Value(childCtx)
1147				diags = append(diags, condDiags...)
1148				if includeRaw.IsNull() {
1149					if known {
1150						diags = append(diags, &hcl.Diagnostic{
1151							Severity:    hcl.DiagError,
1152							Summary:     "Invalid 'for' condition",
1153							Detail:      "The value of the 'if' clause must not be null.",
1154							Subject:     e.CondExpr.Range().Ptr(),
1155							Context:     &e.SrcRange,
1156							Expression:  e.CondExpr,
1157							EvalContext: childCtx,
1158						})
1159					}
1160					known = false
1161					continue
1162				}
1163				if !includeRaw.IsKnown() {
1164					// We will eventually return DynamicVal, but we'll continue
1165					// iterating in case there are other diagnostics to gather
1166					// for later elements.
1167					known = false
1168					continue
1169				}
1170
1171				include, err := convert.Convert(includeRaw, cty.Bool)
1172				if err != nil {
1173					if known {
1174						diags = append(diags, &hcl.Diagnostic{
1175							Severity:    hcl.DiagError,
1176							Summary:     "Invalid 'for' condition",
1177							Detail:      fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
1178							Subject:     e.CondExpr.Range().Ptr(),
1179							Context:     &e.SrcRange,
1180							Expression:  e.CondExpr,
1181							EvalContext: childCtx,
1182						})
1183					}
1184					known = false
1185					continue
1186				}
1187
1188				if include.False() {
1189					// Skip this element
1190					continue
1191				}
1192			}
1193
1194			val, valDiags := e.ValExpr.Value(childCtx)
1195			diags = append(diags, valDiags...)
1196			vals = append(vals, val)
1197		}
1198
1199		if !known {
1200			return cty.DynamicVal, diags
1201		}
1202
1203		return cty.TupleVal(vals), diags
1204	}
1205}
1206
1207func (e *ForExpr) walkChildNodes(w internalWalkFunc) {
1208	w(e.CollExpr)
1209
1210	scopeNames := map[string]struct{}{}
1211	if e.KeyVar != "" {
1212		scopeNames[e.KeyVar] = struct{}{}
1213	}
1214	if e.ValVar != "" {
1215		scopeNames[e.ValVar] = struct{}{}
1216	}
1217
1218	if e.KeyExpr != nil {
1219		w(ChildScope{
1220			LocalNames: scopeNames,
1221			Expr:       e.KeyExpr,
1222		})
1223	}
1224	w(ChildScope{
1225		LocalNames: scopeNames,
1226		Expr:       e.ValExpr,
1227	})
1228	if e.CondExpr != nil {
1229		w(ChildScope{
1230			LocalNames: scopeNames,
1231			Expr:       e.CondExpr,
1232		})
1233	}
1234}
1235
1236func (e *ForExpr) Range() hcl.Range {
1237	return e.SrcRange
1238}
1239
1240func (e *ForExpr) StartRange() hcl.Range {
1241	return e.OpenRange
1242}
1243
1244type SplatExpr struct {
1245	Source Expression
1246	Each   Expression
1247	Item   *AnonSymbolExpr
1248
1249	SrcRange    hcl.Range
1250	MarkerRange hcl.Range
1251}
1252
1253func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1254	sourceVal, diags := e.Source.Value(ctx)
1255	if diags.HasErrors() {
1256		// We'll evaluate our "Each" expression here just to see if it
1257		// produces any more diagnostics we can report. Since we're not
1258		// assigning a value to our AnonSymbolExpr here it will return
1259		// DynamicVal, which should short-circuit any use of it.
1260		_, itemDiags := e.Item.Value(ctx)
1261		diags = append(diags, itemDiags...)
1262		return cty.DynamicVal, diags
1263	}
1264
1265	sourceTy := sourceVal.Type()
1266	if sourceTy == cty.DynamicPseudoType {
1267		// If we don't even know the _type_ of our source value yet then
1268		// we'll need to defer all processing, since we can't decide our
1269		// result type either.
1270		return cty.DynamicVal, diags
1271	}
1272
1273	// A "special power" of splat expressions is that they can be applied
1274	// both to tuples/lists and to other values, and in the latter case
1275	// the value will be treated as an implicit single-item tuple, or as
1276	// an empty tuple if the value is null.
1277	autoUpgrade := !(sourceTy.IsTupleType() || sourceTy.IsListType() || sourceTy.IsSetType())
1278
1279	if sourceVal.IsNull() {
1280		if autoUpgrade {
1281			return cty.EmptyTupleVal, diags
1282		}
1283		diags = append(diags, &hcl.Diagnostic{
1284			Severity:    hcl.DiagError,
1285			Summary:     "Splat of null value",
1286			Detail:      "Splat expressions (with the * symbol) cannot be applied to null sequences.",
1287			Subject:     e.Source.Range().Ptr(),
1288			Context:     hcl.RangeBetween(e.Source.Range(), e.MarkerRange).Ptr(),
1289			Expression:  e.Source,
1290			EvalContext: ctx,
1291		})
1292		return cty.DynamicVal, diags
1293	}
1294
1295	if autoUpgrade {
1296		sourceVal = cty.TupleVal([]cty.Value{sourceVal})
1297		sourceTy = sourceVal.Type()
1298	}
1299
1300	// We'll compute our result type lazily if we need it. In the normal case
1301	// it's inferred automatically from the value we construct.
1302	resultTy := func() (cty.Type, hcl.Diagnostics) {
1303		chiCtx := ctx.NewChild()
1304		var diags hcl.Diagnostics
1305		switch {
1306		case sourceTy.IsListType() || sourceTy.IsSetType():
1307			ety := sourceTy.ElementType()
1308			e.Item.setValue(chiCtx, cty.UnknownVal(ety))
1309			val, itemDiags := e.Each.Value(chiCtx)
1310			diags = append(diags, itemDiags...)
1311			e.Item.clearValue(chiCtx) // clean up our temporary value
1312			return cty.List(val.Type()), diags
1313		case sourceTy.IsTupleType():
1314			etys := sourceTy.TupleElementTypes()
1315			resultTys := make([]cty.Type, 0, len(etys))
1316			for _, ety := range etys {
1317				e.Item.setValue(chiCtx, cty.UnknownVal(ety))
1318				val, itemDiags := e.Each.Value(chiCtx)
1319				diags = append(diags, itemDiags...)
1320				e.Item.clearValue(chiCtx) // clean up our temporary value
1321				resultTys = append(resultTys, val.Type())
1322			}
1323			return cty.Tuple(resultTys), diags
1324		default:
1325			// Should never happen because of our promotion to list above.
1326			return cty.DynamicPseudoType, diags
1327		}
1328	}
1329
1330	if !sourceVal.IsKnown() {
1331		// We can't produce a known result in this case, but we'll still
1332		// indicate what the result type would be, allowing any downstream type
1333		// checking to proceed.
1334		ty, tyDiags := resultTy()
1335		diags = append(diags, tyDiags...)
1336		return cty.UnknownVal(ty), diags
1337	}
1338
1339	vals := make([]cty.Value, 0, sourceVal.LengthInt())
1340	it := sourceVal.ElementIterator()
1341	if ctx == nil {
1342		// we need a context to use our AnonSymbolExpr, so we'll just
1343		// make an empty one here to use as a placeholder.
1344		ctx = ctx.NewChild()
1345	}
1346	isKnown := true
1347	for it.Next() {
1348		_, sourceItem := it.Element()
1349		e.Item.setValue(ctx, sourceItem)
1350		newItem, itemDiags := e.Each.Value(ctx)
1351		diags = append(diags, itemDiags...)
1352		if itemDiags.HasErrors() {
1353			isKnown = false
1354		}
1355		vals = append(vals, newItem)
1356	}
1357	e.Item.clearValue(ctx) // clean up our temporary value
1358
1359	if !isKnown {
1360		// We'll ingore the resultTy diagnostics in this case since they
1361		// will just be the same errors we saw while iterating above.
1362		ty, _ := resultTy()
1363		return cty.UnknownVal(ty), diags
1364	}
1365
1366	switch {
1367	case sourceTy.IsListType() || sourceTy.IsSetType():
1368		if len(vals) == 0 {
1369			ty, tyDiags := resultTy()
1370			diags = append(diags, tyDiags...)
1371			return cty.ListValEmpty(ty.ElementType()), diags
1372		}
1373		return cty.ListVal(vals), diags
1374	default:
1375		return cty.TupleVal(vals), diags
1376	}
1377}
1378
1379func (e *SplatExpr) walkChildNodes(w internalWalkFunc) {
1380	w(e.Source)
1381	w(e.Each)
1382}
1383
1384func (e *SplatExpr) Range() hcl.Range {
1385	return e.SrcRange
1386}
1387
1388func (e *SplatExpr) StartRange() hcl.Range {
1389	return e.MarkerRange
1390}
1391
1392// AnonSymbolExpr is used as a placeholder for a value in an expression that
1393// can be applied dynamically to any value at runtime.
1394//
1395// This is a rather odd, synthetic expression. It is used as part of the
1396// representation of splat expressions as a placeholder for the current item
1397// being visited in the splat evaluation.
1398//
1399// AnonSymbolExpr cannot be evaluated in isolation. If its Value is called
1400// directly then cty.DynamicVal will be returned. Instead, it is evaluated
1401// in terms of another node (i.e. a splat expression) which temporarily
1402// assigns it a value.
1403type AnonSymbolExpr struct {
1404	SrcRange hcl.Range
1405
1406	// values and its associated lock are used to isolate concurrent
1407	// evaluations of a symbol from one another. It is the calling application's
1408	// responsibility to ensure that the same splat expression is not evalauted
1409	// concurrently within the _same_ EvalContext, but it is fine and safe to
1410	// do cuncurrent evaluations with distinct EvalContexts.
1411	values     map[*hcl.EvalContext]cty.Value
1412	valuesLock sync.RWMutex
1413}
1414
1415func (e *AnonSymbolExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1416	if ctx == nil {
1417		return cty.DynamicVal, nil
1418	}
1419
1420	e.valuesLock.RLock()
1421	defer e.valuesLock.RUnlock()
1422
1423	val, exists := e.values[ctx]
1424	if !exists {
1425		return cty.DynamicVal, nil
1426	}
1427	return val, nil
1428}
1429
1430// setValue sets a temporary local value for the expression when evaluated
1431// in the given context, which must be non-nil.
1432func (e *AnonSymbolExpr) setValue(ctx *hcl.EvalContext, val cty.Value) {
1433	e.valuesLock.Lock()
1434	defer e.valuesLock.Unlock()
1435
1436	if e.values == nil {
1437		e.values = make(map[*hcl.EvalContext]cty.Value)
1438	}
1439	if ctx == nil {
1440		panic("can't setValue for a nil EvalContext")
1441	}
1442	e.values[ctx] = val
1443}
1444
1445func (e *AnonSymbolExpr) clearValue(ctx *hcl.EvalContext) {
1446	e.valuesLock.Lock()
1447	defer e.valuesLock.Unlock()
1448
1449	if e.values == nil {
1450		return
1451	}
1452	if ctx == nil {
1453		panic("can't clearValue for a nil EvalContext")
1454	}
1455	delete(e.values, ctx)
1456}
1457
1458func (e *AnonSymbolExpr) walkChildNodes(w internalWalkFunc) {
1459	// AnonSymbolExpr is a leaf node in the tree
1460}
1461
1462func (e *AnonSymbolExpr) Range() hcl.Range {
1463	return e.SrcRange
1464}
1465
1466func (e *AnonSymbolExpr) StartRange() hcl.Range {
1467	return e.SrcRange
1468}
1469