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, }, {