@@ -27,6 +27,7 @@ type Variable struct {
2727 // ConstraintType is used for decoding and type conversions, and may
2828 // contain nested ObjectWithOptionalAttr types.
2929 ConstraintType cty.Type
30+ TypeDefaults * typeexpr.Defaults
3031
3132 ParsingMode VariableParsingMode
3233 Validations []* CheckRule
@@ -102,9 +103,10 @@ func decodeVariableBlock(block *hcl.Block, override bool) (*Variable, hcl.Diagno
102103 }
103104
104105 if attr , exists := content .Attributes ["type" ]; exists {
105- ty , parseMode , tyDiags := decodeVariableType (attr .Expr )
106+ ty , tyDefaults , parseMode , tyDiags := decodeVariableType (attr .Expr )
106107 diags = append (diags , tyDiags ... )
107108 v .ConstraintType = ty
109+ v .TypeDefaults = tyDefaults
108110 v .Type = ty .WithoutOptionalAttributesDeep ()
109111 v .ParsingMode = parseMode
110112 }
@@ -137,6 +139,11 @@ func decodeVariableBlock(block *hcl.Block, override bool) (*Variable, hcl.Diagno
137139 // the type might not be set; we'll catch that during merge.
138140 if v .ConstraintType != cty .NilType {
139141 var err error
142+ // If the type constraint has defaults, we must apply those
143+ // defaults to the variable default value before type conversion.
144+ if v .TypeDefaults != nil {
145+ val = v .TypeDefaults .Apply (val )
146+ }
140147 val , err = convert .Convert (val , v .ConstraintType )
141148 if err != nil {
142149 diags = append (diags , & hcl.Diagnostic {
@@ -179,7 +186,7 @@ func decodeVariableBlock(block *hcl.Block, override bool) (*Variable, hcl.Diagno
179186 return v , diags
180187}
181188
182- func decodeVariableType (expr hcl.Expression ) (cty.Type , VariableParsingMode , hcl.Diagnostics ) {
189+ func decodeVariableType (expr hcl.Expression ) (cty.Type , * typeexpr. Defaults , VariableParsingMode , hcl.Diagnostics ) {
183190 if exprIsNativeQuotedString (expr ) {
184191 // If a user provides the pre-0.12 form of variable type argument where
185192 // the string values "string", "list" and "map" are accepted, we
@@ -190,7 +197,7 @@ func decodeVariableType(expr hcl.Expression) (cty.Type, VariableParsingMode, hcl
190197 // in the normal codepath below.
191198 val , diags := expr .Value (nil )
192199 if diags .HasErrors () {
193- return cty .DynamicPseudoType , VariableParseHCL , diags
200+ return cty .DynamicPseudoType , nil , VariableParseHCL , diags
194201 }
195202 str := val .AsString ()
196203 switch str {
@@ -201,25 +208,25 @@ func decodeVariableType(expr hcl.Expression) (cty.Type, VariableParsingMode, hcl
201208 Detail : "Terraform 0.11 and earlier required type constraints to be given in quotes, but that form is now deprecated and will be removed in a future version of Terraform. Remove the quotes around \" string\" ." ,
202209 Subject : expr .Range ().Ptr (),
203210 })
204- return cty .DynamicPseudoType , VariableParseLiteral , diags
211+ return cty .DynamicPseudoType , nil , VariableParseLiteral , diags
205212 case "list" :
206213 diags = append (diags , & hcl.Diagnostic {
207214 Severity : hcl .DiagError ,
208215 Summary : "Invalid quoted type constraints" ,
209216 Detail : "Terraform 0.11 and earlier required type constraints to be given in quotes, but that form is now deprecated and will be removed in a future version of Terraform. Remove the quotes around \" list\" and write list(string) instead to explicitly indicate that the list elements are strings." ,
210217 Subject : expr .Range ().Ptr (),
211218 })
212- return cty .DynamicPseudoType , VariableParseHCL , diags
219+ return cty .DynamicPseudoType , nil , VariableParseHCL , diags
213220 case "map" :
214221 diags = append (diags , & hcl.Diagnostic {
215222 Severity : hcl .DiagError ,
216223 Summary : "Invalid quoted type constraints" ,
217224 Detail : "Terraform 0.11 and earlier required type constraints to be given in quotes, but that form is now deprecated and will be removed in a future version of Terraform. Remove the quotes around \" map\" and write map(string) instead to explicitly indicate that the map elements are strings." ,
218225 Subject : expr .Range ().Ptr (),
219226 })
220- return cty .DynamicPseudoType , VariableParseHCL , diags
227+ return cty .DynamicPseudoType , nil , VariableParseHCL , diags
221228 default :
222- return cty .DynamicPseudoType , VariableParseHCL , hcl.Diagnostics {{
229+ return cty .DynamicPseudoType , nil , VariableParseHCL , hcl.Diagnostics {{
223230 Severity : hcl .DiagError ,
224231 Summary : "Invalid legacy variable type hint" ,
225232 Detail : `To provide a full type expression, remove the surrounding quotes and give the type expression directly.` ,
@@ -234,23 +241,23 @@ func decodeVariableType(expr hcl.Expression) (cty.Type, VariableParsingMode, hcl
234241 // elements are consistent. This is the same as list(any) or map(any).
235242 switch hcl .ExprAsKeyword (expr ) {
236243 case "list" :
237- return cty .List (cty .DynamicPseudoType ), VariableParseHCL , nil
244+ return cty .List (cty .DynamicPseudoType ), nil , VariableParseHCL , nil
238245 case "map" :
239- return cty .Map (cty .DynamicPseudoType ), VariableParseHCL , nil
246+ return cty .Map (cty .DynamicPseudoType ), nil , VariableParseHCL , nil
240247 }
241248
242- ty , diags := typeexpr .TypeConstraint (expr )
249+ ty , typeDefaults , diags := typeexpr .TypeConstraintWithDefaults (expr )
243250 if diags .HasErrors () {
244- return cty .DynamicPseudoType , VariableParseHCL , diags
251+ return cty .DynamicPseudoType , nil , VariableParseHCL , diags
245252 }
246253
247254 switch {
248255 case ty .IsPrimitiveType ():
249256 // Primitive types use literal parsing.
250- return ty , VariableParseLiteral , diags
257+ return ty , typeDefaults , VariableParseLiteral , diags
251258 default :
252259 // Everything else uses HCL parsing
253- return ty , VariableParseHCL , diags
260+ return ty , typeDefaults , VariableParseHCL , diags
254261 }
255262}
256263
0 commit comments