Skip to content

Commit 783936f

Browse files
authored
Merge pull request #28067 from hashicorp/alisdair/defaults-fix-null-structural-types
functions: Fix defaults for null objects/tuples
2 parents 8a77f3f + 7f97bd4 commit 783936f

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

lang/funcs/defaults.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ func defaultsApply(input, fallback cty.Value) cty.Value {
9494
return v
9595

9696
case wantTy.IsObjectType():
97+
// For structural types, a null input value must be passed through. We
98+
// do not apply default values for missing optional structural values,
99+
// only their contents.
100+
//
101+
// We also pass through the input if the fallback value is null. This
102+
// can happen if the given defaults do not include a value for this
103+
// attribute.
104+
if input.IsNull() || fallback.IsNull() {
105+
return input
106+
}
97107
atys := wantTy.AttributeTypes()
98108
ret := map[string]cty.Value{}
99109
for attr, aty := range atys {
@@ -107,6 +117,17 @@ func defaultsApply(input, fallback cty.Value) cty.Value {
107117
return cty.ObjectVal(ret)
108118

109119
case wantTy.IsTupleType():
120+
// For structural types, a null input value must be passed through. We
121+
// do not apply default values for missing optional structural values,
122+
// only their contents.
123+
//
124+
// We also pass through the input if the fallback value is null. This
125+
// can happen if the given defaults do not include a value for this
126+
// attribute.
127+
if input.IsNull() || fallback.IsNull() {
128+
return input
129+
}
130+
110131
l := wantTy.Length()
111132
ret := make([]cty.Value, l)
112133
for i := 0; i < l; i++ {

lang/funcs/defaults_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,79 @@ func TestDefaults(t *testing.T) {
370370
Defaults: cty.StringVal("hello"),
371371
WantErr: `only object types and collections of object types can have defaults applied`,
372372
},
373+
// When applying default values to structural types, null objects or
374+
// tuples in the input should be passed through.
375+
{
376+
Input: cty.ObjectVal(map[string]cty.Value{
377+
"a": cty.NullVal(cty.Object(map[string]cty.Type{
378+
"x": cty.String,
379+
"y": cty.String,
380+
})),
381+
"b": cty.NullVal(cty.Tuple([]cty.Type{cty.String, cty.String})),
382+
}),
383+
Defaults: cty.ObjectVal(map[string]cty.Value{
384+
"a": cty.ObjectVal(map[string]cty.Value{
385+
"x": cty.StringVal("hello"),
386+
"y": cty.StringVal("there"),
387+
}),
388+
"b": cty.TupleVal([]cty.Value{
389+
cty.StringVal("how are"),
390+
cty.StringVal("you?"),
391+
}),
392+
}),
393+
Want: cty.ObjectVal(map[string]cty.Value{
394+
"a": cty.NullVal(cty.Object(map[string]cty.Type{
395+
"x": cty.String,
396+
"y": cty.String,
397+
})),
398+
"b": cty.NullVal(cty.Tuple([]cty.Type{cty.String, cty.String})),
399+
}),
400+
},
401+
// When applying default values to structural types, we permit null
402+
// values in the defaults, and just pass through the input value.
403+
{
404+
Input: cty.ObjectVal(map[string]cty.Value{
405+
"a": cty.ListVal([]cty.Value{
406+
cty.ObjectVal(map[string]cty.Value{
407+
"p": cty.StringVal("xyz"),
408+
"q": cty.StringVal("xyz"),
409+
}),
410+
}),
411+
"b": cty.SetVal([]cty.Value{
412+
cty.TupleVal([]cty.Value{
413+
cty.NumberIntVal(0),
414+
cty.NumberIntVal(2),
415+
}),
416+
cty.TupleVal([]cty.Value{
417+
cty.NumberIntVal(1),
418+
cty.NumberIntVal(3),
419+
}),
420+
}),
421+
"c": cty.NullVal(cty.String),
422+
}),
423+
Defaults: cty.ObjectVal(map[string]cty.Value{
424+
"c": cty.StringVal("tada"),
425+
}),
426+
Want: cty.ObjectVal(map[string]cty.Value{
427+
"a": cty.ListVal([]cty.Value{
428+
cty.ObjectVal(map[string]cty.Value{
429+
"p": cty.StringVal("xyz"),
430+
"q": cty.StringVal("xyz"),
431+
}),
432+
}),
433+
"b": cty.SetVal([]cty.Value{
434+
cty.TupleVal([]cty.Value{
435+
cty.NumberIntVal(0),
436+
cty.NumberIntVal(2),
437+
}),
438+
cty.TupleVal([]cty.Value{
439+
cty.NumberIntVal(1),
440+
cty.NumberIntVal(3),
441+
}),
442+
}),
443+
"c": cty.StringVal("tada"),
444+
}),
445+
},
373446
// When applying default values to collection types, null collections in the
374447
// input should result in empty collections in the output.
375448
{

0 commit comments

Comments
 (0)