Merge pull request #21576 from hashicorp/mildwonkey/b-matchkeys

lang/funcs: fix error when `matchkeys` encountered a variable
This commit is contained in:
Kristin Laemmert 2019-06-04 12:19:09 -04:00 committed by GitHub
commit 2d194828a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 9 deletions

View File

@ -800,10 +800,12 @@ var MatchkeysFunc = function.New(&function.Spec{
}, },
}, },
Type: func(args []cty.Value) (cty.Type, error) { Type: func(args []cty.Value) (cty.Type, error) {
if !args[1].Type().Equals(args[2].Type()) { ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
return cty.NilType, errors.New("lists must be of the same type") if ty == cty.NilType {
return cty.NilType, errors.New("keys and searchset must be of the same type")
} }
// the return type is based on args[0] (values)
return args[0].Type(), nil return args[0].Type(), nil
}, },
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
@ -816,10 +818,14 @@ var MatchkeysFunc = function.New(&function.Spec{
} }
output := make([]cty.Value, 0) output := make([]cty.Value, 0)
values := args[0] values := args[0]
keys := args[1]
searchset := args[2] // Keys and searchset must be the same type.
// We can skip error checking here because we've already verified that
// they can be unified in the Type function
ty, _ := convert.UnifyUnsafe([]cty.Type{args[1].Type(), args[2].Type()})
keys, _ := convert.Convert(args[1], ty)
searchset, _ := convert.Convert(args[2], ty)
// if searchset is empty, return an empty list. // if searchset is empty, return an empty list.
if searchset.LengthInt() == 0 { if searchset.LengthInt() == 0 {

View File

@ -1883,8 +1883,7 @@ func TestMatchkeys(t *testing.T) {
cty.UnknownVal(cty.List(cty.String)), cty.UnknownVal(cty.List(cty.String)),
false, false,
}, },
// errors { // different types that can be unified
{ // different types
cty.ListVal([]cty.Value{ cty.ListVal([]cty.Value{
cty.StringVal("a"), cty.StringVal("a"),
}), }),
@ -1894,9 +1893,41 @@ func TestMatchkeys(t *testing.T) {
cty.ListVal([]cty.Value{ cty.ListVal([]cty.Value{
cty.StringVal("a"), cty.StringVal("a"),
}), }),
cty.NilVal, cty.ListValEmpty(cty.String),
true, false,
}, },
{ // complex values: values is a different type from keys and searchset
cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
}),
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("baz"),
}),
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("beep"),
}),
}),
cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b"),
cty.StringVal("c"),
}),
cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("c"),
}),
cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
}),
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("beep"),
}),
}),
false,
},
// errors
{ // different types { // different types
cty.ListVal([]cty.Value{ cty.ListVal([]cty.Value{
cty.StringVal("a"), cty.StringVal("a"),

View File

@ -459,6 +459,13 @@ func TestFunctions(t *testing.T) {
cty.StringVal("a"), cty.StringVal("a"),
}), }),
}, },
{ // mixing types in searchset
`matchkeys(["a", "b", "c"], [1, 2, 3], [1, "3"])`,
cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("c"),
}),
},
}, },
"max": { "max": {