]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/hcl2/ext/typeexpr/get_type.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / hcl2 / ext / typeexpr / get_type.go
1 package typeexpr
2
3 import (
4 "fmt"
5
6 "github.com/hashicorp/hcl2/hcl"
7 "github.com/zclconf/go-cty/cty"
8 )
9
10 const invalidTypeSummary = "Invalid type specification"
11
12 // getType is the internal implementation of both Type and TypeConstraint,
13 // using the passed flag to distinguish. When constraint is false, the "any"
14 // keyword will produce an error.
15 func getType(expr hcl.Expression, constraint bool) (cty.Type, hcl.Diagnostics) {
16 // First we'll try for one of our keywords
17 kw := hcl.ExprAsKeyword(expr)
18 switch kw {
19 case "bool":
20 return cty.Bool, nil
21 case "string":
22 return cty.String, nil
23 case "number":
24 return cty.Number, nil
25 case "any":
26 if constraint {
27 return cty.DynamicPseudoType, nil
28 }
29 return cty.DynamicPseudoType, hcl.Diagnostics{{
30 Severity: hcl.DiagError,
31 Summary: invalidTypeSummary,
32 Detail: fmt.Sprintf("The keyword %q cannot be used in this type specification: an exact type is required.", kw),
33 Subject: expr.Range().Ptr(),
34 }}
35 case "list", "map", "set":
36 return cty.DynamicPseudoType, hcl.Diagnostics{{
37 Severity: hcl.DiagError,
38 Summary: invalidTypeSummary,
39 Detail: fmt.Sprintf("The %s type constructor requires one argument specifying the element type.", kw),
40 Subject: expr.Range().Ptr(),
41 }}
42 case "object":
43 return cty.DynamicPseudoType, hcl.Diagnostics{{
44 Severity: hcl.DiagError,
45 Summary: invalidTypeSummary,
46 Detail: "The object type constructor requires one argument specifying the attribute types and values as a map.",
47 Subject: expr.Range().Ptr(),
48 }}
49 case "tuple":
50 return cty.DynamicPseudoType, hcl.Diagnostics{{
51 Severity: hcl.DiagError,
52 Summary: invalidTypeSummary,
53 Detail: "The tuple type constructor requires one argument specifying the element types as a list.",
54 Subject: expr.Range().Ptr(),
55 }}
56 case "":
57 // okay! we'll fall through and try processing as a call, then.
58 default:
59 return cty.DynamicPseudoType, hcl.Diagnostics{{
60 Severity: hcl.DiagError,
61 Summary: invalidTypeSummary,
62 Detail: fmt.Sprintf("The keyword %q is not a valid type specification.", kw),
63 Subject: expr.Range().Ptr(),
64 }}
65 }
66
67 // If we get down here then our expression isn't just a keyword, so we'll
68 // try to process it as a call instead.
69 call, diags := hcl.ExprCall(expr)
70 if diags.HasErrors() {
71 return cty.DynamicPseudoType, hcl.Diagnostics{{
72 Severity: hcl.DiagError,
73 Summary: invalidTypeSummary,
74 Detail: "A type specification is either a primitive type keyword (bool, number, string) or a complex type constructor call, like list(string).",
75 Subject: expr.Range().Ptr(),
76 }}
77 }
78
79 switch call.Name {
80 case "bool", "string", "number", "any":
81 return cty.DynamicPseudoType, hcl.Diagnostics{{
82 Severity: hcl.DiagError,
83 Summary: invalidTypeSummary,
84 Detail: fmt.Sprintf("Primitive type keyword %q does not expect arguments.", call.Name),
85 Subject: &call.ArgsRange,
86 }}
87 }
88
89 if len(call.Arguments) != 1 {
90 contextRange := call.ArgsRange
91 subjectRange := call.ArgsRange
92 if len(call.Arguments) > 1 {
93 // If we have too many arguments (as opposed to too _few_) then
94 // we'll highlight the extraneous arguments as the diagnostic
95 // subject.
96 subjectRange = hcl.RangeBetween(call.Arguments[1].Range(), call.Arguments[len(call.Arguments)-1].Range())
97 }
98
99 switch call.Name {
100 case "list", "set", "map":
101 return cty.DynamicPseudoType, hcl.Diagnostics{{
102 Severity: hcl.DiagError,
103 Summary: invalidTypeSummary,
104 Detail: fmt.Sprintf("The %s type constructor requires one argument specifying the element type.", call.Name),
105 Subject: &subjectRange,
106 Context: &contextRange,
107 }}
108 case "object":
109 return cty.DynamicPseudoType, hcl.Diagnostics{{
110 Severity: hcl.DiagError,
111 Summary: invalidTypeSummary,
112 Detail: "The object type constructor requires one argument specifying the attribute types and values as a map.",
113 Subject: &subjectRange,
114 Context: &contextRange,
115 }}
116 case "tuple":
117 return cty.DynamicPseudoType, hcl.Diagnostics{{
118 Severity: hcl.DiagError,
119 Summary: invalidTypeSummary,
120 Detail: "The tuple type constructor requires one argument specifying the element types as a list.",
121 Subject: &subjectRange,
122 Context: &contextRange,
123 }}
124 }
125 }
126
127 switch call.Name {
128
129 case "list":
130 ety, diags := getType(call.Arguments[0], constraint)
131 return cty.List(ety), diags
132 case "set":
133 ety, diags := getType(call.Arguments[0], constraint)
134 return cty.Set(ety), diags
135 case "map":
136 ety, diags := getType(call.Arguments[0], constraint)
137 return cty.Map(ety), diags
138 case "object":
139 attrDefs, diags := hcl.ExprMap(call.Arguments[0])
140 if diags.HasErrors() {
141 return cty.DynamicPseudoType, hcl.Diagnostics{{
142 Severity: hcl.DiagError,
143 Summary: invalidTypeSummary,
144 Detail: "Object type constructor requires a map whose keys are attribute names and whose values are the corresponding attribute types.",
145 Subject: call.Arguments[0].Range().Ptr(),
146 Context: expr.Range().Ptr(),
147 }}
148 }
149
150 atys := make(map[string]cty.Type)
151 for _, attrDef := range attrDefs {
152 attrName := hcl.ExprAsKeyword(attrDef.Key)
153 if attrName == "" {
154 diags = append(diags, &hcl.Diagnostic{
155 Severity: hcl.DiagError,
156 Summary: invalidTypeSummary,
157 Detail: "Object constructor map keys must be attribute names.",
158 Subject: attrDef.Key.Range().Ptr(),
159 Context: expr.Range().Ptr(),
160 })
161 continue
162 }
163 aty, attrDiags := getType(attrDef.Value, constraint)
164 diags = append(diags, attrDiags...)
165 atys[attrName] = aty
166 }
167 return cty.Object(atys), diags
168 case "tuple":
169 elemDefs, diags := hcl.ExprList(call.Arguments[0])
170 if diags.HasErrors() {
171 return cty.DynamicPseudoType, hcl.Diagnostics{{
172 Severity: hcl.DiagError,
173 Summary: invalidTypeSummary,
174 Detail: "Tuple type constructor requires a list of element types.",
175 Subject: call.Arguments[0].Range().Ptr(),
176 Context: expr.Range().Ptr(),
177 }}
178 }
179 etys := make([]cty.Type, len(elemDefs))
180 for i, defExpr := range elemDefs {
181 ety, elemDiags := getType(defExpr, constraint)
182 diags = append(diags, elemDiags...)
183 etys[i] = ety
184 }
185 return cty.Tuple(etys), diags
186 default:
187 // Can't access call.Arguments in this path because we've not validated
188 // that it contains exactly one expression here.
189 return cty.DynamicPseudoType, hcl.Diagnostics{{
190 Severity: hcl.DiagError,
191 Summary: invalidTypeSummary,
192 Detail: fmt.Sprintf("Keyword %q is not a valid type constructor.", call.Name),
193 Subject: expr.Range().Ptr(),
194 }}
195 }
196 }