functions: Fix defaults for null objects/tuples

When using defaults with a value which contains null objects or tuples,
we cannot continue to traverse the value and apply defaults. Instead,
when we find an attribute which is null, we return early and stop
processing this branch.
This commit is contained in:
Alisdair McDiarmid 2021-03-12 08:19:55 -05:00
parent 42c6c5dd6c
commit 0bbe583eb8
2 changed files with 41 additions and 0 deletions

View File

@ -94,6 +94,12 @@ func defaultsApply(input, fallback cty.Value) cty.Value {
return v return v
case wantTy.IsObjectType(): case wantTy.IsObjectType():
// For structural types, a null input value must be passed through. We
// do not apply default values for missing optional structural values,
// only their contents.
if input.IsNull() {
return input
}
atys := wantTy.AttributeTypes() atys := wantTy.AttributeTypes()
ret := map[string]cty.Value{} ret := map[string]cty.Value{}
for attr, aty := range atys { for attr, aty := range atys {
@ -107,6 +113,13 @@ func defaultsApply(input, fallback cty.Value) cty.Value {
return cty.ObjectVal(ret) return cty.ObjectVal(ret)
case wantTy.IsTupleType(): case wantTy.IsTupleType():
// For structural types, a null input value must be passed through. We
// do not apply default values for missing optional structural values,
// only their contents.
if input.IsNull() {
return input
}
l := wantTy.Length() l := wantTy.Length()
ret := make([]cty.Value, l) ret := make([]cty.Value, l)
for i := 0; i < l; i++ { for i := 0; i < l; i++ {

View File

@ -370,6 +370,34 @@ func TestDefaults(t *testing.T) {
Defaults: cty.StringVal("hello"), Defaults: cty.StringVal("hello"),
WantErr: `only object types and collections of object types can have defaults applied`, WantErr: `only object types and collections of object types can have defaults applied`,
}, },
// When applying default values to structural types, null objects or
// tuples in the input should be passed through.
{
Input: cty.ObjectVal(map[string]cty.Value{
"a": cty.NullVal(cty.Object(map[string]cty.Type{
"x": cty.String,
"y": cty.String,
})),
"b": cty.NullVal(cty.Tuple([]cty.Type{cty.String, cty.String})),
}),
Defaults: cty.ObjectVal(map[string]cty.Value{
"a": cty.ObjectVal(map[string]cty.Value{
"x": cty.StringVal("hello"),
"y": cty.StringVal("there"),
}),
"b": cty.TupleVal([]cty.Value{
cty.StringVal("how are"),
cty.StringVal("you?"),
}),
}),
Want: cty.ObjectVal(map[string]cty.Value{
"a": cty.NullVal(cty.Object(map[string]cty.Type{
"x": cty.String,
"y": cty.String,
})),
"b": cty.NullVal(cty.Tuple([]cty.Type{cty.String, cty.String})),
}),
},
// When applying default values to collection types, null collections in the // When applying default values to collection types, null collections in the
// input should result in empty collections in the output. // input should result in empty collections in the output.
{ {