Skip to content

Commit

Permalink
convert: fix panic when converting nested objects
Browse files Browse the repository at this point in the history
When converting a list of objects, it is necessary to unify the types of
the child elements.
  • Loading branch information
mildwonkey authored May 18, 2020
1 parent 8158450 commit 174b1b4
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
41 changes: 41 additions & 0 deletions cty/convert/conversion_collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ func conversionTupleToList(tupleType cty.Type, listEty cty.Type, unsafe bool) co
// element conversions in elemConvs
return func(val cty.Value, path cty.Path) (cty.Value, error) {
elems := make([]cty.Value, 0, len(elemConvs))
elemTys := make([]cty.Type, 0, len(elems))
elemPath := append(path.Copy(), nil)
i := int64(0)
it := val.ElementIterator()
Expand All @@ -284,10 +285,15 @@ func conversionTupleToList(tupleType cty.Type, listEty cty.Type, unsafe bool) co
}
}
elems = append(elems, val)
elemTys = append(elemTys, val.Type())

i++
}

elems, err := conversionUnifyListElements(elems, elemPath, unsafe)
if err != nil {
return cty.NilVal, err
}
return cty.ListVal(elems), nil
}
}
Expand Down Expand Up @@ -441,6 +447,7 @@ func conversionUnifyCollectionElements(elems map[string]cty.Value, path cty.Path
}
unifiedType, _ := unify(elemTypes, unsafe)
if unifiedType == cty.NilType {
return nil, path.NewErrorf("collection elements cannot be unified")
}

unifiedElems := make(map[string]cty.Value)
Expand Down Expand Up @@ -486,3 +493,37 @@ func conversionCheckMapElementTypes(elems map[string]cty.Value, path cty.Path) e

return nil
}

func conversionUnifyListElements(elems []cty.Value, path cty.Path, unsafe bool) ([]cty.Value, error) {
elemTypes := make([]cty.Type, len(elems))
for i, elem := range elems {
elemTypes[i] = elem.Type()
}
unifiedType, _ := unify(elemTypes, unsafe)
if unifiedType == cty.NilType {
return nil, path.NewErrorf("collection elements cannot be unified")
}

ret := make([]cty.Value, len(elems))
elemPath := append(path.Copy(), nil)

for i, elem := range elems {
if elem.Type().Equals(unifiedType) {
ret[i] = elem
continue
}
conv := getConversion(elem.Type(), unifiedType, unsafe)
if conv == nil {
}
elemPath[len(elemPath)-1] = cty.IndexStep{
Key: cty.NumberIntVal(int64(i)),
}
val, err := conv(elem, elemPath)
if err != nil {
return nil, err
}
ret[i] = val
}

return ret, nil
}
28 changes: 28 additions & 0 deletions cty/convert/public_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,34 @@ func TestConvert(t *testing.T) {
"b": cty.MapValEmpty(cty.String),
}),
},
// https://github.com/hashicorp/terraform/issues/21588:
{
Value: cty.TupleVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"a": cty.EmptyObjectVal,
"b": cty.NumberIntVal(2),
}),
cty.ObjectVal(map[string]cty.Value{
"a": cty.ObjectVal(map[string]cty.Value{"var1": cty.StringVal("val1")}),
"b": cty.StringVal("2"),
}),
}),
Type: cty.List(cty.Object(map[string]cty.Type{
"a": cty.DynamicPseudoType,
"b": cty.String,
})),
Want: cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"a": cty.MapValEmpty(cty.String),
"b": cty.StringVal("2"),
}),
cty.ObjectVal(map[string]cty.Value{
"a": cty.MapVal(map[string]cty.Value{"var1": cty.StringVal("val1")}),
"b": cty.StringVal("2"),
}),
}),
WantError: false,
},
}

for _, test := range tests {
Expand Down

0 comments on commit 174b1b4

Please sign in to comment.