Skip to content

Commit

Permalink
refinements of collections must use Range()
Browse files Browse the repository at this point in the history
When attempting to determine the final length range for a conditional
expression with collections, the length values may still be unknown.
Always use `Range()` to get the lower and upper bounds.
  • Loading branch information
jbardin committed Oct 11, 2023
1 parent 63067e8 commit b6b3dba
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 9 deletions.
16 changes: 7 additions & 9 deletions hclsyntax/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -725,16 +725,14 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
falseLen := falseResult.Length()
if gt := trueLen.GreaterThan(falseLen); gt.IsKnown() {
b := cty.UnknownVal(resultType).Refine()
trueLen, _ := trueLen.AsBigFloat().Int64()
falseLen, _ := falseLen.AsBigFloat().Int64()
if gt.True() {
b = b.
CollectionLengthLowerBound(int(falseLen)).
CollectionLengthUpperBound(int(trueLen))
CollectionLengthLowerBound(falseResult.Range().LengthLowerBound()).
CollectionLengthUpperBound(trueResult.Range().LengthUpperBound())
} else {
b = b.
CollectionLengthLowerBound(int(trueLen)).
CollectionLengthUpperBound(int(falseLen))
CollectionLengthLowerBound(trueResult.Range().LengthLowerBound()).
CollectionLengthUpperBound(falseResult.Range().LengthUpperBound())
}
b = b.NotNull() // If neither of the results is null then the result can't be either
return b.NewValue().WithSameMarks(condResult).WithSameMarks(trueResult).WithSameMarks(falseResult), diags
Expand Down Expand Up @@ -1244,9 +1242,9 @@ func (e *ObjectConsKeyExpr) UnwrapExpression() Expression {

// ForExpr represents iteration constructs:
//
// tuple = [for i, v in list: upper(v) if i > 2]
// object = {for k, v in map: k => upper(v)}
// object_of_tuples = {for v in list: v.key: v...}
// tuple = [for i, v in list: upper(v) if i > 2]
// object = {for k, v in map: k => upper(v)}
// object_of_tuples = {for v in list: v.key: v...}
type ForExpr struct {
KeyVar string // empty if ignoring the key
ValVar string
Expand Down
14 changes: 14 additions & 0 deletions hclsyntax/expression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,20 @@ EOT
cty.ListValEmpty(cty.String), // deduced through refinements
0,
},
{
`unknown ? ar : br`,
&hcl.EvalContext{
Variables: map[string]cty.Value{
"unknown": cty.UnknownVal(cty.Bool),
"ar": cty.UnknownVal(cty.Set(cty.String)).Refine().
CollectionLengthLowerBound(1).CollectionLengthUpperBound(2).NewValue(),
"br": cty.UnknownVal(cty.Set(cty.String)).Refine().
CollectionLengthLowerBound(3).CollectionLengthUpperBound(4).NewValue(),
},
},
cty.UnknownVal(cty.Set(cty.String)).Refine().NotNull().CollectionLengthLowerBound(1).CollectionLengthUpperBound(4).NewValue(), // deduced through refinements
0,
},
{
`unknown ? a : b`,
&hcl.EvalContext{
Expand Down

0 comments on commit b6b3dba

Please sign in to comment.