From fe026c3c98000969f47d983aadd4e45f027b5f3f Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Fri, 18 Dec 2020 14:22:42 -0500 Subject: [PATCH] hclsyntax: Fix for expression marked conditional Using marked values in a for expression conditional expression would previously panic due to calling `.False()` on the result of the expression. This commit makes two changes: - Unmark the conditional expression value before testing if it is false; - Merge any marks from the conditional into the resulting marks for the for expression. --- hclsyntax/expression.go | 24 ++++++++++++++++++++++-- hclsyntax/expression_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/hclsyntax/expression.go b/hclsyntax/expression.go index 7917853..6c590b4 100644 --- a/hclsyntax/expression.go +++ b/hclsyntax/expression.go @@ -1143,7 +1143,17 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { continue } - if include.False() { + // Extract and merge marks from the include expression into the + // main set of marks + includeUnmarked, includeMarks := include.Unmark() + if marks == nil { + marks = includeMarks + } else { + for k := range includeMarks { + marks[k] = struct{}{} + } + } + if includeUnmarked.False() { // Skip this element continue } @@ -1300,7 +1310,17 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { continue } - if include.False() { + // Extract and merge marks from the include expression into the + // main set of marks + includeUnmarked, includeMarks := include.Unmark() + if marks == nil { + marks = includeMarks + } else { + for k := range includeMarks { + marks[k] = struct{}{} + } + } + if includeUnmarked.False() { // Skip this element continue } diff --git a/hclsyntax/expression_test.go b/hclsyntax/expression_test.go index 89805fc..743bb6c 100644 --- a/hclsyntax/expression_test.go +++ b/hclsyntax/expression_test.go @@ -933,6 +933,42 @@ upper( }), 1, }, + { // Sequence for loop with marked conditional expression + `[for x in things: x if x != secret]`, + &hcl.EvalContext{ + Variables: map[string]cty.Value{ + "things": cty.ListVal([]cty.Value{ + cty.StringVal("a"), + cty.StringVal("b"), + cty.StringVal("c"), + }), + "secret": cty.StringVal("b").Mark("sensitive"), + }, + }, + cty.TupleVal([]cty.Value{ + cty.StringVal("a"), + cty.StringVal("c"), + }).Mark("sensitive"), + 0, + }, + { // Map for loop with marked conditional expression + `{ for k, v in things: k => v if k != secret }`, + &hcl.EvalContext{ + Variables: map[string]cty.Value{ + "things": cty.MapVal(map[string]cty.Value{ + "a": cty.True, + "b": cty.False, + "c": cty.False, + }), + "secret": cty.StringVal("b").Mark("sensitive"), + }, + }, + cty.ObjectVal(map[string]cty.Value{ + "a": cty.True, + "c": cty.False, + }).Mark("sensitive"), + 0, + }, { `[{name: "Steve"}, {name: "Ermintrude"}].*.name`, nil,