govendor fetch github.com/zclconf/go-cty/...

This update includes a new conversion from tuple types to set types and
improvements to the error messages returned when conversions fail.
This commit is contained in:
Martin Atkins 2018-07-18 16:12:02 -07:00
parent f77dd12e5c
commit aa6b55bb17
14 changed files with 172 additions and 35 deletions

View File

@ -19,7 +19,7 @@ func (t *capsuleType) Equals(other Type) bool {
return false
}
func (t *capsuleType) FriendlyName() string {
func (t *capsuleType) FriendlyName(mode friendlyTypeNameMode) string {
return t.Name
}

View File

@ -109,6 +109,10 @@ func getConversionKnown(in cty.Type, out cty.Type, unsafe bool) conversion {
outEty := out.ElementType()
return conversionTupleToList(in, outEty, unsafe)
case out.IsSetType() && in.IsTupleType():
outEty := out.ElementType()
return conversionTupleToSet(in, outEty, unsafe)
case out.IsMapType() && in.IsObjectType():
outEty := out.ElementType()
return conversionObjectToMap(in, outEty, unsafe)

View File

@ -128,6 +128,76 @@ func conversionCollectionToMap(ety cty.Type, conv conversion) conversion {
}
}
// conversionTupleToSet returns a conversion that will take a value of the
// given tuple type and return a set of the given element type.
//
// Will panic if the given tupleType isn't actually a tuple type.
func conversionTupleToSet(tupleType cty.Type, listEty cty.Type, unsafe bool) conversion {
tupleEtys := tupleType.TupleElementTypes()
if len(tupleEtys) == 0 {
// Empty tuple short-circuit
return func(val cty.Value, path cty.Path) (cty.Value, error) {
return cty.ListValEmpty(listEty), nil
}
}
if listEty == cty.DynamicPseudoType {
// This is a special case where the caller wants us to find
// a suitable single type that all elements can convert to, if
// possible.
listEty, _ = unify(tupleEtys, unsafe)
if listEty == cty.NilType {
return nil
}
}
elemConvs := make([]conversion, len(tupleEtys))
for i, tupleEty := range tupleEtys {
if tupleEty.Equals(listEty) {
// no conversion required
continue
}
elemConvs[i] = getConversion(tupleEty, listEty, unsafe)
if elemConvs[i] == nil {
// If any of our element conversions are impossible, then the our
// whole conversion is impossible.
return nil
}
}
// If we fall out here then a conversion is possible, using the
// element conversions in elemConvs
return func(val cty.Value, path cty.Path) (cty.Value, error) {
elems := make([]cty.Value, 0, len(elemConvs))
path = append(path, nil)
i := int64(0)
it := val.ElementIterator()
for it.Next() {
_, val := it.Element()
var err error
path[len(path)-1] = cty.IndexStep{
Key: cty.NumberIntVal(i),
}
conv := elemConvs[i]
if conv != nil {
val, err = conv(val, path)
if err != nil {
return cty.NilVal, err
}
}
elems = append(elems, val)
i++
}
return cty.SetVal(elems), nil
}
}
// conversionTupleToList returns a conversion that will take a value of the
// given tuple type and return a list of the given element type.
//

View File

@ -32,9 +32,24 @@ func MismatchMessage(got, want cty.Type) string {
// about their respective attributes.
return mismatchMessageObjects(got, want)
case got.IsTupleType() && want.IsListType() && want.ElementType() == cty.DynamicPseudoType:
// If conversion from tuple to list failed then it's because we couldn't
// find a common type to convert all of the tuple elements to.
return "all list elements must have the same type"
case got.IsTupleType() && want.IsSetType() && want.ElementType() == cty.DynamicPseudoType:
// If conversion from tuple to set failed then it's because we couldn't
// find a common type to convert all of the tuple elements to.
return "all set elements must have the same type"
case got.IsObjectType() && want.IsMapType() && want.ElementType() == cty.DynamicPseudoType:
// If conversion from object to map failed then it's because we couldn't
// find a common type to convert all of the object attributes to.
return "all map elements must have the same type"
default:
// If we have nothing better to say, we'll just state what was required.
return want.FriendlyName() + " required"
return want.FriendlyNameForConstraint() + " required"
}
}

View File

@ -103,11 +103,11 @@ func (t *Type) GobDecode(buf []byte) error {
// Capsule types cannot currently be gob-encoded, because they rely on pointer
// equality and we have no way to recover the original pointer on decode.
func (t *capsuleType) GobEncode() ([]byte, error) {
return nil, fmt.Errorf("cannot gob-encode capsule type %q", t.FriendlyName())
return nil, fmt.Errorf("cannot gob-encode capsule type %q", t.FriendlyName(friendlyTypeName))
}
func (t *capsuleType) GobDecode() ([]byte, error) {
return nil, fmt.Errorf("cannot gob-decode capsule type %q", t.FriendlyName())
return nil, fmt.Errorf("cannot gob-decode capsule type %q", t.FriendlyName(friendlyTypeName))
}
type gobValue struct {

View File

@ -33,8 +33,14 @@ func (t typeList) Equals(other Type) bool {
return t.ElementTypeT.Equals(ot.ElementTypeT)
}
func (t typeList) FriendlyName() string {
return "list of " + t.ElementTypeT.FriendlyName()
func (t typeList) FriendlyName(mode friendlyTypeNameMode) string {
elemName := t.ElementTypeT.friendlyNameMode(mode)
if mode == friendlyTypeConstraintName {
if t.ElementTypeT == DynamicPseudoType {
elemName = "any single type"
}
}
return "list of " + elemName
}
func (t typeList) ElementType() Type {

View File

@ -33,8 +33,14 @@ func (t typeMap) Equals(other Type) bool {
return t.ElementTypeT.Equals(ot.ElementTypeT)
}
func (t typeMap) FriendlyName() string {
return "map of " + t.ElementTypeT.FriendlyName()
func (t typeMap) FriendlyName(mode friendlyTypeNameMode) string {
elemName := t.ElementTypeT.friendlyNameMode(mode)
if mode == friendlyTypeConstraintName {
if t.ElementTypeT == DynamicPseudoType {
elemName = "any single type"
}
}
return "map of " + elemName
}
func (t typeMap) ElementType() Type {

View File

@ -51,7 +51,7 @@ func (t typeObject) Equals(other Type) bool {
return false
}
func (t typeObject) FriendlyName() string {
func (t typeObject) FriendlyName(mode friendlyTypeNameMode) string {
// There isn't really a friendly way to write an object type due to its
// complexity, so we'll just do something English-ish. Callers will
// probably want to make some extra effort to avoid ever printing out

View File

@ -24,7 +24,7 @@ func (t primitiveType) Equals(other Type) bool {
return false
}
func (t primitiveType) FriendlyName() string {
func (t primitiveType) FriendlyName(mode friendlyTypeNameMode) string {
switch t.Kind {
case primitiveTypeBool:
return "bool"

View File

@ -31,8 +31,14 @@ func (t typeSet) Equals(other Type) bool {
return t.ElementTypeT.Equals(ot.ElementTypeT)
}
func (t typeSet) FriendlyName() string {
return "set of " + t.ElementTypeT.FriendlyName()
func (t typeSet) FriendlyName(mode friendlyTypeNameMode) string {
elemName := t.ElementTypeT.friendlyNameMode(mode)
if mode == friendlyTypeConstraintName {
if t.ElementTypeT == DynamicPseudoType {
elemName = "any single type"
}
}
return "set of " + elemName
}
func (t typeSet) ElementType() Type {

View File

@ -44,7 +44,7 @@ func (t typeTuple) Equals(other Type) bool {
return false
}
func (t typeTuple) FriendlyName() string {
func (t typeTuple) FriendlyName(mode friendlyTypeNameMode) string {
// There isn't really a friendly way to write a tuple type due to its
// complexity, so we'll just do something English-ish. Callers will
// probably want to make some extra effort to avoid ever printing out

View File

@ -19,7 +19,7 @@ type typeImpl interface {
// FriendlyName returns a human-friendly *English* name for the given
// type.
FriendlyName() string
FriendlyName(mode friendlyTypeNameMode) string
// GoString implements the GoStringer interface from package fmt.
GoString() string
@ -41,7 +41,25 @@ func (t Type) Equals(other Type) bool {
// FriendlyName returns a human-friendly *English* name for the given type.
func (t Type) FriendlyName() string {
return t.typeImpl.FriendlyName()
return t.typeImpl.FriendlyName(friendlyTypeName)
}
// FriendlyNameForConstraint is similar to FriendlyName except that the
// result is specialized for describing type _constraints_ rather than types
// themselves. This is more appropriate when reporting that a particular value
// does not conform to an expected type constraint.
//
// In particular, this function uses the term "any type" to refer to
// cty.DynamicPseudoType, rather than "dynamic" as returned by FriendlyName.
func (t Type) FriendlyNameForConstraint() string {
return t.typeImpl.FriendlyName(friendlyTypeConstraintName)
}
// friendlyNameMode is an internal combination of the various FriendlyName*
// variants that just directly takes a mode, for easy passthrough for
// recursive name construction.
func (t Type) friendlyNameMode(mode friendlyTypeNameMode) string {
return t.typeImpl.FriendlyName(mode)
}
// GoString returns a string approximating how the receiver type would be
@ -93,3 +111,10 @@ func (t Type) HasDynamicTypes() bool {
panic("HasDynamicTypes does not support the given type")
}
}
type friendlyTypeNameMode rune
const (
friendlyTypeName friendlyTypeNameMode = 'N'
friendlyTypeConstraintName friendlyTypeNameMode = 'C'
)

View File

@ -54,8 +54,13 @@ func (t pseudoTypeDynamic) Equals(other Type) bool {
return ok
}
func (t pseudoTypeDynamic) FriendlyName() string {
return "dynamic"
func (t pseudoTypeDynamic) FriendlyName(mode friendlyTypeNameMode) string {
switch mode {
case friendlyTypeConstraintName:
return "any type"
default:
return "dynamic"
}
}
func (t pseudoTypeDynamic) GoString() string {

36
vendor/vendor.json vendored
View File

@ -2464,52 +2464,52 @@
"revisionTime": "2016-10-29T10:40:18Z"
},
{
"checksumSHA1": "4REWNRi5Dg7Kxj1US72+/oVii3Q=",
"checksumSHA1": "Ej+3WWvyjn0xg3aujsyT+yvvmdc=",
"path": "github.com/zclconf/go-cty/cty",
"revision": "3ccef1ae92b0ac73b92d86f274f0ff781e2d9b3b",
"revisionTime": "2018-07-07T01:23:34Z"
"revision": "02bd58e97b5759d478019c5a6333edbfdfed16a0",
"revisionTime": "2018-07-18T22:05:26Z"
},
{
"checksumSHA1": "3bFMqSB6IxIwhzIw8hyLfd7ayrY=",
"checksumSHA1": "1WGUPe776lvMMbaRerAbqOx19nQ=",
"path": "github.com/zclconf/go-cty/cty/convert",
"revision": "3ccef1ae92b0ac73b92d86f274f0ff781e2d9b3b",
"revisionTime": "2018-07-07T01:23:34Z"
"revision": "02bd58e97b5759d478019c5a6333edbfdfed16a0",
"revisionTime": "2018-07-18T22:05:26Z"
},
{
"checksumSHA1": "MyyLCGg3RREMllTJyK6ehZl/dHk=",
"path": "github.com/zclconf/go-cty/cty/function",
"revision": "3ccef1ae92b0ac73b92d86f274f0ff781e2d9b3b",
"revisionTime": "2018-07-07T01:23:34Z"
"revision": "02bd58e97b5759d478019c5a6333edbfdfed16a0",
"revisionTime": "2018-07-18T22:05:26Z"
},
{
"checksumSHA1": "kcTJOuL131/stXJ4U9tC3SASQLs=",
"path": "github.com/zclconf/go-cty/cty/function/stdlib",
"revision": "3ccef1ae92b0ac73b92d86f274f0ff781e2d9b3b",
"revisionTime": "2018-07-07T01:23:34Z"
"revision": "02bd58e97b5759d478019c5a6333edbfdfed16a0",
"revisionTime": "2018-07-18T22:05:26Z"
},
{
"checksumSHA1": "tmCzwfNXOEB1sSO7TKVzilb2vjA=",
"path": "github.com/zclconf/go-cty/cty/gocty",
"revision": "3ccef1ae92b0ac73b92d86f274f0ff781e2d9b3b",
"revisionTime": "2018-07-07T01:23:34Z"
"revision": "02bd58e97b5759d478019c5a6333edbfdfed16a0",
"revisionTime": "2018-07-18T22:05:26Z"
},
{
"checksumSHA1": "1ApmO+Q33+Oem/3f6BU6sztJWNc=",
"path": "github.com/zclconf/go-cty/cty/json",
"revision": "3ccef1ae92b0ac73b92d86f274f0ff781e2d9b3b",
"revisionTime": "2018-07-07T01:23:34Z"
"revision": "02bd58e97b5759d478019c5a6333edbfdfed16a0",
"revisionTime": "2018-07-18T22:05:26Z"
},
{
"checksumSHA1": "8H+2pufGi2Eo3d8cXFfJs31wk+I=",
"path": "github.com/zclconf/go-cty/cty/msgpack",
"revision": "3ccef1ae92b0ac73b92d86f274f0ff781e2d9b3b",
"revisionTime": "2018-07-07T01:23:34Z"
"revision": "02bd58e97b5759d478019c5a6333edbfdfed16a0",
"revisionTime": "2018-07-18T22:05:26Z"
},
{
"checksumSHA1": "y5Sk+n6SOspFj8mlyb8swr4DMIs=",
"path": "github.com/zclconf/go-cty/cty/set",
"revision": "3ccef1ae92b0ac73b92d86f274f0ff781e2d9b3b",
"revisionTime": "2018-07-07T01:23:34Z"
"revision": "02bd58e97b5759d478019c5a6333edbfdfed16a0",
"revisionTime": "2018-07-18T22:05:26Z"
},
{
"checksumSHA1": "vE43s37+4CJ2CDU6TlOUOYE0K9c=",