From fadd95cd914c8aaf0a7099d058777e22935c7660 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 1 Dec 2021 11:38:11 -0500 Subject: [PATCH] unknown upgraded splat values may have no elems When upgrading an unknown splat value, the resulting collection may have 0 elements if the value ends up being `null`. This means the type must be dynamic. --- hclsyntax/expression.go | 14 +++++++++----- hclsyntax/expression_test.go | 18 +++++++++++++++--- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/hclsyntax/expression.go b/hclsyntax/expression.go index 72a2e6d9..07464a6b 100644 --- a/hclsyntax/expression.go +++ b/hclsyntax/expression.go @@ -1439,10 +1439,10 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { // upgrade to a different number of elements depending on whether // sourceVal becomes null or not. // We record this condition here so we can process any remaining - // expression after the * to derive the correct type. For example, it - // is valid to use a splat on a single object to retrieve a list of a - // single attribute, which means the final expression type still needs - // to be determined. + // expression after the * to verify the result of the traversal. For + // example, it is valid to use a splat on a single object to retrieve a + // list of a single attribute, but we still need to check if that + // attribute actually exists. upgradedUnknown = !sourceVal.IsKnown() sourceVal = cty.TupleVal([]cty.Value{sourceVal}) @@ -1512,7 +1512,11 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { } e.Item.clearValue(ctx) // clean up our temporary value - if !isKnown || upgradedUnknown { + if upgradedUnknown { + return cty.DynamicVal, diags + } + + if !isKnown { // We'll ingore the resultTy diagnostics in this case since they // will just be the same errors we saw while iterating above. ty, _ := resultTy() diff --git a/hclsyntax/expression_test.go b/hclsyntax/expression_test.go index c1f4c6fe..4636ede0 100644 --- a/hclsyntax/expression_test.go +++ b/hclsyntax/expression_test.go @@ -1142,7 +1142,7 @@ upper( "unkstr": cty.UnknownVal(cty.String), }, }, - cty.UnknownVal(cty.Tuple([]cty.Type{cty.String})), + cty.DynamicVal, 0, }, { @@ -1152,7 +1152,7 @@ upper( "unkstr": cty.UnknownVal(cty.String), }, }, - cty.UnknownVal(cty.Tuple([]cty.Type{cty.DynamicPseudoType})), + cty.DynamicVal, 1, // a string has no attribute "name" }, { @@ -1174,7 +1174,19 @@ upper( })), }, }, - cty.UnknownVal(cty.Tuple([]cty.Type{cty.String})), + cty.DynamicVal, + 0, + }, + { + `unkobj.*.names`, + &hcl.EvalContext{ + Variables: map[string]cty.Value{ + "unkobj": cty.UnknownVal(cty.Object(map[string]cty.Type{ + "names": cty.List(cty.String), + })), + }, + }, + cty.DynamicVal, 0, }, {