From 178a9b32d7eee889e12d402ec066edbcdc0d96b6 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Thu, 4 Mar 2021 10:13:41 -0500 Subject: [PATCH] functions: Fix defaults null collections panic When applying default values to collection types, null collections in the input should result in empty collections in the output. --- lang/funcs/defaults.go | 18 +++++++++++------- lang/funcs/defaults_test.go | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/lang/funcs/defaults.go b/lang/funcs/defaults.go index 0366ea6614..0f9a8eb12a 100644 --- a/lang/funcs/defaults.go +++ b/lang/funcs/defaults.go @@ -127,9 +127,11 @@ func defaultsApply(input, fallback cty.Value) cty.Value { case wantTy.IsMapType(): newVals := map[string]cty.Value{} - for it := input.ElementIterator(); it.Next(); { - k, v := it.Element() - newVals[k.AsString()] = defaultsApply(v, fallback) + if !input.IsNull() { + for it := input.ElementIterator(); it.Next(); { + k, v := it.Element() + newVals[k.AsString()] = defaultsApply(v, fallback) + } } if len(newVals) == 0 { @@ -139,10 +141,12 @@ func defaultsApply(input, fallback cty.Value) cty.Value { case wantTy.IsListType(), wantTy.IsSetType(): var newVals []cty.Value - for it := input.ElementIterator(); it.Next(); { - _, v := it.Element() - newV := defaultsApply(v, fallback) - newVals = append(newVals, newV) + if !input.IsNull() { + for it := input.ElementIterator(); it.Next(); { + _, v := it.Element() + newV := defaultsApply(v, fallback) + newVals = append(newVals, newV) + } } if len(newVals) == 0 { diff --git a/lang/funcs/defaults_test.go b/lang/funcs/defaults_test.go index ca0c3be65d..efa5c1c9bb 100644 --- a/lang/funcs/defaults_test.go +++ b/lang/funcs/defaults_test.go @@ -370,6 +370,25 @@ func TestDefaults(t *testing.T) { Defaults: cty.StringVal("hello"), WantErr: `only object types and collections of object types can have defaults applied`, }, + // When applying default values to collection types, null collections in the + // input should result in empty collections in the output. + { + Input: cty.ObjectVal(map[string]cty.Value{ + "a": cty.NullVal(cty.List(cty.String)), + "b": cty.NullVal(cty.Map(cty.String)), + "c": cty.NullVal(cty.Set(cty.String)), + }), + Defaults: cty.ObjectVal(map[string]cty.Value{ + "a": cty.StringVal("hello"), + "b": cty.StringVal("hi"), + "c": cty.StringVal("greetings"), + }), + Want: cty.ObjectVal(map[string]cty.Value{ + "a": cty.ListValEmpty(cty.String), + "b": cty.MapValEmpty(cty.String), + "c": cty.SetValEmpty(cty.String), + }), + }, } for _, test := range tests {