summaryrefslogtreecommitdiff
path: root/ext/dynblock/expr_wrap.go
diff options
context:
space:
mode:
authorMartin Atkins <mart@degeneration.co.uk>2024-05-08 17:52:51 -0700
committerMartin Atkins <mart@degeneration.co.uk>2024-05-09 11:32:15 -0700
commit9a64c17c75059d9c8f5d94f2265c00026ac48781 (patch)
tree9d67ba69c4ea52eeeb7a0288df657b9a2cf3af4f /ext/dynblock/expr_wrap.go
parentbc757658ca11c5d6d17f328d5672ac447c3efcff (diff)
dynblock: Preserve marks from for_each expression into result
Previously if the for_each expression was marked then expansion would fail because marked expressions are never directly iterable. Now instead we'll allow marked for_each and preserve the marks into the values produced by the resulting block as much as we can. This runs into the classic problem that HCL blocks are not values themselves and so cannot carry marks directly, but we can at least make sure that the values of any leaf arguments end up marked.
Diffstat (limited to 'ext/dynblock/expr_wrap.go')
-rw-r--r--ext/dynblock/expr_wrap.go24
1 files changed, 23 insertions, 1 deletions
diff --git a/ext/dynblock/expr_wrap.go b/ext/dynblock/expr_wrap.go
index 625bf9c..5763641 100644
--- a/ext/dynblock/expr_wrap.go
+++ b/ext/dynblock/expr_wrap.go
@@ -11,6 +11,19 @@ import (
type exprWrap struct {
hcl.Expression
i *iteration
+
+ // resultMarks is a set of marks that must be applied to whatever
+ // value results from this expression. We do this whenever a
+ // dynamic block's for_each expression produced a marked result,
+ // since in that case any nested expressions inside are treated
+ // as being derived from that for_each expression.
+ //
+ // (calling applications might choose to reject marks by passing
+ // an [OptCheckForEach] to [Expand] and returning an error when
+ // marks are present, but this mechanism is here to help achieve
+ // reasonable behavior for situations where marks are permitted,
+ // which is the default.)
+ resultMarks cty.ValueMarks
}
func (e exprWrap) Variables() []hcl.Traversal {
@@ -34,8 +47,13 @@ func (e exprWrap) Variables() []hcl.Traversal {
}
func (e exprWrap) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
+ if e.i == nil {
+ // If we don't have an active iteration then we can just use the
+ // given EvalContext directly.
+ return e.prepareValue(e.Expression.Value(ctx))
+ }
extCtx := e.i.EvalContext(ctx)
- return e.Expression.Value(extCtx)
+ return e.prepareValue(e.Expression.Value(extCtx))
}
// UnwrapExpression returns the expression being wrapped by this instance.
@@ -43,3 +61,7 @@ func (e exprWrap) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
func (e exprWrap) UnwrapExpression() hcl.Expression {
return e.Expression
}
+
+func (e exprWrap) prepareValue(val cty.Value, diags hcl.Diagnostics) (cty.Value, hcl.Diagnostics) {
+ return val.WithMarks(e.resultMarks), diags
+}