diff --git a/cty/function/stdlib/collection.go b/cty/function/stdlib/collection.go index ad2bb637..dbfd46d0 100644 --- a/cty/function/stdlib/collection.go +++ b/cty/function/stdlib/collection.go @@ -530,6 +530,12 @@ func flattener(flattenList cty.Value) ([]cty.Value, []cty.ValueMarks, bool) { // predict the length of our result yet either. return nil, markses, false } + // Any dynamic types could result in more collection that need to be + // flattened, so the type cannot be known. + if flattenList.Type().HasDynamicTypes() { + return nil, markses, false + } + out := make([]cty.Value, 0) isKnown := true for it := flattenList.ElementIterator(); it.Next(); { diff --git a/cty/function/stdlib/collection_test.go b/cty/function/stdlib/collection_test.go index 5bca5f85..be155526 100644 --- a/cty/function/stdlib/collection_test.go +++ b/cty/function/stdlib/collection_test.go @@ -1928,6 +1928,59 @@ func TestFlatten(t *testing.T) { cty.EmptyTupleVal.Mark("a"), "", }, + { + cty.ListValEmpty(cty.Number), + cty.EmptyTupleVal, + "", + }, + { + cty.ListVal([]cty.Value{ + cty.DynamicVal, + }), + cty.DynamicVal, + "", + }, + { + cty.TupleVal([]cty.Value{ + cty.ListVal([]cty.Value{ + cty.ListVal([]cty.Value{ + cty.DynamicVal, + }), + }), + cty.ListVal([]cty.Value{ + cty.ListVal([]cty.Value{ + cty.DynamicVal, + }).Mark("marked"), + }), + }), + cty.DynamicVal, + "", + }, + { + cty.TupleVal([]cty.Value{ + cty.StringVal("a"), + cty.ListVal([]cty.Value{ + cty.StringVal("b"), + }), + cty.TupleVal([]cty.Value{ + cty.ListVal([]cty.Value{ + cty.StringVal("c"), + }), + cty.ListVal([]cty.Value{ + cty.StringVal("d"), + cty.StringVal("e"), + }), + }), + }), + cty.TupleVal([]cty.Value{ + cty.StringVal("a"), + cty.StringVal("b"), + cty.StringVal("c"), + cty.StringVal("d"), + cty.StringVal("e"), + }), + "", + }, } for _, test := range tests {