hcl: Special error message for indexing a sequence with a fraction

This situation is likely to arise if the user attempts to compute an index
using division while expecting HCL to do integer division rather than
float division.

This message is intended therefore to help the user see what fix is needed
(round the number) but because of layering it sadly cannot suggest a
specific remedy because HCL itself has no built-in rounding functionality,
and thus how exactly that is done is a matter for the calling application.

We're accepting that compromise for now to see how common this turns out
to be in practice. My hypothesis is that it'll be seen more when an
application moves from HCL 1 to HCL 2 because HCL 1 would do integer
division in some cases, but then it will be less common once new patterns
are established in the language community. For example, any existing
examples of using integer division to index in Terraform will over time
be replaced with examples showing the use of Terraform's "floor" function.
This commit is contained in:
Martin Atkins 2019-04-16 09:23:32 -07:00
parent d268d87f93
commit 2c5a4b7d72
2 changed files with 30 additions and 0 deletions

View File

@ -2,6 +2,7 @@ package hcl
import (
"fmt"
"math/big"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/convert"
@ -84,6 +85,27 @@ func Index(collection, key cty.Value, srcRange *Range) (cty.Value, Diagnostics)
}
}
if has.False() {
// We have a more specialized error message for the situation of
// using a fractional number to index into a sequence, because
// that will tend to happen if the user is trying to use division
// to calculate an index and not realizing that HCL does float
// division rather than integer division.
if (ty.IsListType() || ty.IsTupleType()) && key.Type().Equals(cty.Number) {
if key.IsKnown() && !key.IsNull() {
bf := key.AsBigFloat()
if _, acc := bf.Int(nil); acc != big.Exact {
return cty.DynamicVal, Diagnostics{
{
Severity: DiagError,
Summary: "Invalid index",
Detail: fmt.Sprintf("The given key does not identify an element in this collection value: indexing a sequence requires a whole number, but the given index (%g) has a fractional part.", bf),
Subject: srcRange,
},
}
}
}
}
return cty.DynamicVal, Diagnostics{
{
Severity: DiagError,

View File

@ -62,6 +62,14 @@ func TestApplyPath(t *testing.T) {
cty.NilVal,
`Invalid index`,
},
{
cty.ListVal([]cty.Value{
cty.StringVal("hello"),
}),
(cty.Path)(nil).Index(cty.NumberFloatVal(0.5)),
cty.NilVal,
`Invalid index`,
},
{
cty.ListVal([]cty.Value{
cty.StringVal("hello"),