1package cty 2 3// Type represents value types within the type system. 4// 5// This is a closed interface type, meaning that only the concrete 6// implementations provided within this package are considered valid. 7type Type struct { 8 typeImpl 9} 10 11type typeImpl interface { 12 // isTypeImpl is a do-nothing method that exists only to express 13 // that a type is an implementation of typeImpl. 14 isTypeImpl() typeImplSigil 15 16 // Equals returns true if the other given Type exactly equals the 17 // receiver Type. 18 Equals(other Type) bool 19 20 // FriendlyName returns a human-friendly *English* name for the given 21 // type. 22 FriendlyName(mode friendlyTypeNameMode) string 23 24 // GoString implements the GoStringer interface from package fmt. 25 GoString() string 26} 27 28// Base implementation of Type to embed into concrete implementations 29// to signal that they are implementations of Type. 30type typeImplSigil struct{} 31 32func (t typeImplSigil) isTypeImpl() typeImplSigil { 33 return typeImplSigil{} 34} 35 36// Equals returns true if the other given Type exactly equals the receiver 37// type. 38func (t Type) Equals(other Type) bool { 39 return t.typeImpl.Equals(other) 40} 41 42// FriendlyName returns a human-friendly *English* name for the given type. 43func (t Type) FriendlyName() string { 44 return t.typeImpl.FriendlyName(friendlyTypeName) 45} 46 47// FriendlyNameForConstraint is similar to FriendlyName except that the 48// result is specialized for describing type _constraints_ rather than types 49// themselves. This is more appropriate when reporting that a particular value 50// does not conform to an expected type constraint. 51// 52// In particular, this function uses the term "any type" to refer to 53// cty.DynamicPseudoType, rather than "dynamic" as returned by FriendlyName. 54func (t Type) FriendlyNameForConstraint() string { 55 return t.typeImpl.FriendlyName(friendlyTypeConstraintName) 56} 57 58// friendlyNameMode is an internal combination of the various FriendlyName* 59// variants that just directly takes a mode, for easy passthrough for 60// recursive name construction. 61func (t Type) friendlyNameMode(mode friendlyTypeNameMode) string { 62 return t.typeImpl.FriendlyName(mode) 63} 64 65// GoString returns a string approximating how the receiver type would be 66// expressed in Go source code. 67func (t Type) GoString() string { 68 if t.typeImpl == nil { 69 return "cty.NilType" 70 } 71 72 return t.typeImpl.GoString() 73} 74 75// NilType is an invalid type used when a function is returning an error 76// and has no useful type to return. It should not be used and any methods 77// called on it will panic. 78var NilType = Type{} 79 80// HasDynamicTypes returns true either if the receiver is itself 81// DynamicPseudoType or if it is a compound type whose descendent elements 82// are DynamicPseudoType. 83func (t Type) HasDynamicTypes() bool { 84 switch { 85 case t == DynamicPseudoType: 86 return true 87 case t.IsPrimitiveType(): 88 return false 89 case t.IsCollectionType(): 90 return false 91 case t.IsObjectType(): 92 attrTypes := t.AttributeTypes() 93 for _, at := range attrTypes { 94 if at.HasDynamicTypes() { 95 return true 96 } 97 } 98 return false 99 case t.IsTupleType(): 100 elemTypes := t.TupleElementTypes() 101 for _, et := range elemTypes { 102 if et.HasDynamicTypes() { 103 return true 104 } 105 } 106 return false 107 case t.IsCapsuleType(): 108 return false 109 default: 110 // Should never happen, since above should be exhaustive 111 panic("HasDynamicTypes does not support the given type") 112 } 113} 114 115type friendlyTypeNameMode rune 116 117const ( 118 friendlyTypeName friendlyTypeNameMode = 'N' 119 friendlyTypeConstraintName friendlyTypeNameMode = 'C' 120) 121