8 "github.com/hashicorp/hcl2/hcl/hclsyntax"
10 "github.com/hashicorp/hcl2/hcl"
11 "github.com/zclconf/go-cty/cty"
14 // Type attempts to process the given expression as a type expression and, if
15 // successful, returns the resulting type. If unsuccessful, error diagnostics
17 func Type(expr hcl.Expression) (cty.Type, hcl.Diagnostics) {
18 return getType(expr, false)
21 // TypeConstraint attempts to parse the given expression as a type constraint
22 // and, if successful, returns the resulting type. If unsuccessful, error
23 // diagnostics are returned.
25 // A type constraint has the same structure as a type, but it additionally
26 // allows the keyword "any" to represent cty.DynamicPseudoType, which is often
27 // used as a wildcard in type checking and type conversion operations.
28 func TypeConstraint(expr hcl.Expression) (cty.Type, hcl.Diagnostics) {
29 return getType(expr, true)
32 // TypeString returns a string rendering of the given type as it would be
33 // expected to appear in the HCL native syntax.
35 // This is primarily intended for showing types to the user in an application
36 // that uses typexpr, where the user can be assumed to be familiar with the
37 // type expression syntax. In applications that do not use typeexpr these
38 // results may be confusing to the user and so type.FriendlyName may be
39 // preferable, even though it's less precise.
41 // TypeString produces reasonable results only for types like what would be
42 // produced by the Type and TypeConstraint functions. In particular, it cannot
43 // support capsule types.
44 func TypeString(ty cty.Type) string {
53 case cty.DynamicPseudoType:
57 if ty.IsCapsuleType() {
58 panic("TypeString does not support capsule types")
61 if ty.IsCollectionType() {
62 ety := ty.ElementType()
63 etyString := TypeString(ety)
66 return fmt.Sprintf("list(%s)", etyString)
68 return fmt.Sprintf("set(%s)", etyString)
70 return fmt.Sprintf("map(%s)", etyString)
72 // Should never happen because the above is exhaustive
73 panic("unsupported collection type")
77 if ty.IsObjectType() {
79 buf.WriteString("object({")
80 atys := ty.AttributeTypes()
81 names := make([]string, 0, len(atys))
82 for name := range atys {
83 names = append(names, name)
87 for _, name := range names {
92 if !hclsyntax.ValidIdentifier(name) {
93 // Should never happen for any type produced by this package,
94 // but we'll do something reasonable here just so we don't
95 // produce garbage if someone gives us a hand-assembled object
96 // type that has weird attribute names.
97 // Using Go-style quoting here isn't perfect, since it doesn't
98 // exactly match HCL syntax, but it's fine for an edge-case.
99 buf.WriteString(fmt.Sprintf("%q", name))
101 buf.WriteString(name)
104 buf.WriteString(TypeString(aty))
107 buf.WriteString("})")
111 if ty.IsTupleType() {
113 buf.WriteString("tuple([")
114 etys := ty.TupleElementTypes()
116 for _, ety := range etys {
120 buf.WriteString(TypeString(ety))
123 buf.WriteString("])")
127 // Should never happen because we covered all cases above.
128 panic(fmt.Errorf("unsupported type %#v", ty))