bump github.com/zclconf/go-cty from 1.7.1 to 1.10.0

Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2022-01-13 14:32:10 +01:00
parent 785c861233
commit b67bdedb23
30 changed files with 13397 additions and 193 deletions

View File

@ -33,14 +33,25 @@ func getConversion(in cty.Type, out cty.Type, unsafe bool) conversion {
// Conversion to DynamicPseudoType always just passes through verbatim.
return in, nil
}
if !in.IsKnown() {
return cty.UnknownVal(out), nil
}
if in.IsNull() {
// We'll pass through nulls, albeit type converted, and let
// the caller deal with whatever handling they want to do in
// case null values are considered valid in some applications.
return cty.NullVal(out), nil
if isKnown, isNull := in.IsKnown(), in.IsNull(); !isKnown || isNull {
// Avoid constructing unknown or null values with types which
// include optional attributes. Known or non-null object values
// will be passed to a conversion function which drops the optional
// attributes from the type. Unknown and null pass through values
// must do the same to ensure that homogeneous collections have a
// single element type.
out = out.WithoutOptionalAttributesDeep()
if !isKnown {
return cty.UnknownVal(out), nil
}
if isNull {
// We'll pass through nulls, albeit type converted, and let
// the caller deal with whatever handling they want to do in
// case null values are considered valid in some applications.
return cty.NullVal(out), nil
}
}
return conv(in, path)

View File

@ -45,12 +45,18 @@ func conversionCollectionToList(ety cty.Type, conv conversion) conversion {
}
if len(elems) == 0 {
// Prefer a concrete type over a dynamic type when returning an
// empty list
if ety == cty.DynamicPseudoType {
ety = val.Type().ElementType()
return cty.ListValEmpty(val.Type().ElementType()), nil
}
return cty.ListValEmpty(ety), nil
}
if !cty.CanListVal(elems) {
return cty.NilVal, path.NewErrorf("element types must all match for conversion to list")
}
return cty.ListVal(elems), nil
}
}
@ -91,11 +97,15 @@ func conversionCollectionToSet(ety cty.Type, conv conversion) conversion {
// Prefer a concrete type over a dynamic type when returning an
// empty set
if ety == cty.DynamicPseudoType {
ety = val.Type().ElementType()
return cty.SetValEmpty(val.Type().ElementType()), nil
}
return cty.SetValEmpty(ety), nil
}
if !cty.CanSetVal(elems) {
return cty.NilVal, path.NewErrorf("element types must all match for conversion to set")
}
return cty.SetVal(elems), nil
}
}
@ -140,7 +150,7 @@ func conversionCollectionToMap(ety cty.Type, conv conversion) conversion {
// Prefer a concrete type over a dynamic type when returning an
// empty map
if ety == cty.DynamicPseudoType {
ety = val.Type().ElementType()
return cty.MapValEmpty(val.Type().ElementType()), nil
}
return cty.MapValEmpty(ety), nil
}
@ -152,8 +162,8 @@ func conversionCollectionToMap(ety cty.Type, conv conversion) conversion {
}
}
if err := conversionCheckMapElementTypes(elems, path); err != nil {
return cty.NilVal, err
if !cty.CanMapVal(elems) {
return cty.NilVal, path.NewErrorf("element types must all match for conversion to map")
}
return cty.MapVal(elems), nil
@ -237,6 +247,10 @@ func conversionTupleToSet(tupleType cty.Type, setEty cty.Type, unsafe bool) conv
i++
}
if !cty.CanSetVal(elems) {
return cty.NilVal, path.NewErrorf("element types must all match for conversion to set")
}
return cty.SetVal(elems), nil
}
}
@ -324,6 +338,11 @@ func conversionTupleToList(tupleType cty.Type, listEty cty.Type, unsafe bool) co
if err != nil {
return cty.NilVal, err
}
if !cty.CanListVal(elems) {
return cty.NilVal, path.NewErrorf("element types must all match for conversion to list")
}
return cty.ListVal(elems), nil
}
}
@ -402,8 +421,8 @@ func conversionObjectToMap(objectType cty.Type, mapEty cty.Type, unsafe bool) co
}
}
if err := conversionCheckMapElementTypes(elems, path); err != nil {
return cty.NilVal, err
if !cty.CanMapVal(elems) {
return cty.NilVal, path.NewErrorf("attribute types must all match for conversion to map")
}
return cty.MapVal(elems), nil
@ -487,7 +506,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")
return nil, path.NewErrorf("cannot find a common base type for all elements")
}
unifiedElems := make(map[string]cty.Value)
@ -514,26 +533,6 @@ func conversionUnifyCollectionElements(elems map[string]cty.Value, path cty.Path
return unifiedElems, nil
}
func conversionCheckMapElementTypes(elems map[string]cty.Value, path cty.Path) error {
elementType := cty.NilType
elemPath := append(path.Copy(), nil)
for name, elem := range elems {
if elementType == cty.NilType {
elementType = elem.Type()
continue
}
if !elementType.Equals(elem.Type()) {
elemPath[len(elemPath)-1] = cty.IndexStep{
Key: cty.StringVal(name),
}
return elemPath.NewErrorf("%s is required", elementType.FriendlyName())
}
}
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 {
@ -541,7 +540,7 @@ func conversionUnifyListElements(elems []cty.Value, path cty.Path, unsafe bool)
}
unifiedType, _ := unify(elemTypes, unsafe)
if unifiedType == cty.NilType {
return nil, path.NewErrorf("collection elements cannot be unified")
return nil, path.NewErrorf("cannot find a common base type for all elements")
}
ret := make([]cty.Value, len(elems))

View File

@ -29,6 +29,8 @@ func unify(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
// unification purposes.
{
mapCt := 0
listCt := 0
setCt := 0
objectCt := 0
tupleCt := 0
dynamicCt := 0
@ -36,6 +38,10 @@ func unify(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
switch {
case ty.IsMapType():
mapCt++
case ty.IsListType():
listCt++
case ty.IsSetType():
setCt++
case ty.IsObjectType():
objectCt++
case ty.IsTupleType():
@ -48,7 +54,31 @@ func unify(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
}
switch {
case mapCt > 0 && (mapCt+dynamicCt) == len(types):
return unifyMapTypes(types, unsafe, dynamicCt > 0)
return unifyCollectionTypes(cty.Map, types, unsafe, dynamicCt > 0)
case mapCt > 0 && (mapCt+objectCt+dynamicCt) == len(types):
// Objects often contain map data, but are not directly typed as
// such due to language constructs or function types. Try to unify
// them as maps first before falling back to heterogeneous type
// conversion.
ty, convs := unifyObjectsAsMaps(types, unsafe)
// If we got a map back, we know the unification was successful.
if ty.IsMapType() {
return ty, convs
}
case listCt > 0 && (listCt+dynamicCt) == len(types):
return unifyCollectionTypes(cty.List, types, unsafe, dynamicCt > 0)
case listCt > 0 && (listCt+tupleCt+dynamicCt) == len(types):
// Tuples are often lists in disguise, and we may be able to
// unify them as such.
ty, convs := unifyTuplesAsList(types, unsafe)
// if we got a list back, we know the unification was successful.
// Otherwise we will fall back to the heterogeneous type codepath.
if ty.IsListType() {
return ty, convs
}
case setCt > 0 && (setCt+dynamicCt) == len(types):
return unifyCollectionTypes(cty.Set, types, unsafe, dynamicCt > 0)
case objectCt > 0 && (objectCt+dynamicCt) == len(types):
return unifyObjectTypes(types, unsafe, dynamicCt > 0)
case tupleCt > 0 && (tupleCt+dynamicCt) == len(types):
@ -100,7 +130,121 @@ Preferences:
return cty.NilType, nil
}
func unifyMapTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) {
// unifyTuplesAsList attempts to first see if the tuples unify as lists, then
// re-unifies the given types with the list in place of the tuples.
func unifyTuplesAsList(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
var tuples []cty.Type
var tupleIdxs []int
for i, t := range types {
if t.IsTupleType() {
tuples = append(tuples, t)
tupleIdxs = append(tupleIdxs, i)
}
}
ty, tupleConvs := unifyTupleTypesToList(tuples, unsafe)
if !ty.IsListType() {
return cty.NilType, nil
}
// the tuples themselves unified as a list, get the overall
// unification with this list type instead of the tuple.
// make a copy of the types, so we can fallback to the standard
// codepath if something went wrong
listed := make([]cty.Type, len(types))
copy(listed, types)
for _, idx := range tupleIdxs {
listed[idx] = ty
}
newTy, convs := unify(listed, unsafe)
if !newTy.IsListType() {
return cty.NilType, nil
}
// we have a good conversion, wrap the nested tuple conversions.
// We know the tuple conversion is not nil, because we went from tuple to
// list
for i, idx := range tupleIdxs {
listConv := convs[idx]
tupleConv := tupleConvs[i]
if listConv == nil {
convs[idx] = tupleConv
continue
}
convs[idx] = func(in cty.Value) (out cty.Value, err error) {
out, err = tupleConv(in)
if err != nil {
return out, err
}
return listConv(in)
}
}
return newTy, convs
}
// unifyObjectsAsMaps attempts to first see if the objects unify as maps, then
// re-unifies the given types with the map in place of the objects.
func unifyObjectsAsMaps(types []cty.Type, unsafe bool) (cty.Type, []Conversion) {
var objs []cty.Type
var objIdxs []int
for i, t := range types {
if t.IsObjectType() {
objs = append(objs, t)
objIdxs = append(objIdxs, i)
}
}
ty, objConvs := unifyObjectTypesToMap(objs, unsafe)
if !ty.IsMapType() {
return cty.NilType, nil
}
// the objects themselves unified as a map, get the overall
// unification with this map type instead of the object.
// Make a copy of the types, so we can fallback to the standard codepath if
// something went wrong without changing the original types.
mapped := make([]cty.Type, len(types))
copy(mapped, types)
for _, idx := range objIdxs {
mapped[idx] = ty
}
newTy, convs := unify(mapped, unsafe)
if !newTy.IsMapType() {
return cty.NilType, nil
}
// we have a good conversion, so wrap the nested object conversions.
// We know the object conversion is not nil, because we went from object to
// map.
for i, idx := range objIdxs {
mapConv := convs[idx]
objConv := objConvs[i]
if mapConv == nil {
convs[idx] = objConv
continue
}
convs[idx] = func(in cty.Value) (out cty.Value, err error) {
out, err = objConv(in)
if err != nil {
return out, err
}
return mapConv(in)
}
}
return newTy, convs
}
func unifyCollectionTypes(collectionType func(cty.Type) cty.Type, types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []Conversion) {
// If we had any dynamic types in the input here then we can't predict
// what path we'll take through here once these become known types, so
// we'll conservatively produce DynamicVal for these.
@ -117,7 +261,7 @@ func unifyMapTypes(types []cty.Type, unsafe bool, hasDynamic bool) (cty.Type, []
return cty.NilType, nil
}
retTy := cty.Map(retElemType)
retTy := collectionType(retElemType)
conversions := make([]Conversion, len(types))
for i, ty := range types {