functions: Fix defaults mismatched types fallback

We allow primitive fallback values which have mismatched types, but only
if there is a conversion to the target type. Previously we would allow
unsafe conversions (e.g. string to bool), but later had no capacity to
return an error if the conversion failed due to the value of the
fallback being unable to convert to the target type.

This commit makes the more conservative requirement that default
fallback values must have a safe conversion.
This commit is contained in:
Alisdair McDiarmid 2021-03-04 10:41:02 -05:00
parent 178a9b32d7
commit 66f8d1c1c2
2 changed files with 33 additions and 1 deletions

View File

@ -187,7 +187,7 @@ func defaultsAssertSuitableFallback(wantTy, fallbackTy cty.Type, fallbackPath ct
if fallbackTy.Equals(wantTy) {
return nil
}
conversion := convert.GetConversionUnsafe(fallbackTy, wantTy)
conversion := convert.GetConversion(fallbackTy, wantTy)
if conversion == nil {
msg := convert.MismatchMessage(fallbackTy, wantTy)
return fallbackPath.NewErrorf("invalid default value for %s: %s", wantTy.FriendlyName(), msg)

View File

@ -389,6 +389,38 @@ func TestDefaults(t *testing.T) {
"c": cty.SetValEmpty(cty.String),
}),
},
// When specifying fallbacks, we allow mismatched primitive attribute
// types so long as a safe conversion is possible. This means that we
// can accept number or boolean values for string attributes.
{
Input: cty.ObjectVal(map[string]cty.Value{
"a": cty.NullVal(cty.String),
"b": cty.NullVal(cty.String),
"c": cty.NullVal(cty.String),
}),
Defaults: cty.ObjectVal(map[string]cty.Value{
"a": cty.NumberIntVal(5),
"b": cty.True,
"c": cty.StringVal("greetings"),
}),
Want: cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("5"),
"b": cty.StringVal("true"),
"c": cty.StringVal("greetings"),
}),
},
// Fallbacks with mismatched primitive attribute types which do not
// have safe conversions must not pass the suitable fallback check,
// even if unsafe conversion would be possible.
{
Input: cty.ObjectVal(map[string]cty.Value{
"a": cty.NullVal(cty.Bool),
}),
Defaults: cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("5"),
}),
WantErr: ".a: invalid default value for bool: bool required",
},
}
for _, test := range tests {