29
29
initNone # None of the fields have been initialized
30
30
initConflict # Fields from different branches have been initialized
31
31
32
+
33
+ proc semConstructFields (c: PContext , n: PNode , constrCtx: var ObjConstrContext ,
34
+ flags: TExprFlags ): tuple [status: InitStatus , defaults: seq [PNode ]]
35
+
32
36
proc mergeInitStatus (existing: var InitStatus , newStatus: InitStatus ) =
33
37
case newStatus
34
38
of initConflict:
@@ -72,7 +76,9 @@ proc semConstrField(c: PContext, flags: TExprFlags,
72
76
let assignment = locateFieldInInitExpr (c, field, initExpr)
73
77
if assignment != nil :
74
78
if nfSem in assignment.flags: return assignment[1 ]
75
- if not fieldVisible (c, field):
79
+ if nfUseDefaultField in assignment[1 ].flags:
80
+ discard
81
+ elif not fieldVisible (c, field):
76
82
localError (c.config, initExpr.info,
77
83
" the field '$1' is not accessible." % [field.name.s])
78
84
return
@@ -155,18 +161,14 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode,
155
161
if assignment == nil :
156
162
constrCtx.missingFields.add r.sym
157
163
158
-
159
- proc semConstructFields (c: PContext , n: PNode ,
160
- constrCtx: var ObjConstrContext ,
161
- flags: TExprFlags ): InitStatus =
162
- result = initUnknown
163
-
164
+ proc semConstructFields (c: PContext , n: PNode , constrCtx: var ObjConstrContext ,
165
+ flags: TExprFlags ): tuple [status: InitStatus , defaults: seq [PNode ]] =
164
166
case n.kind
165
167
of nkRecList:
166
168
for field in n:
167
- let status = semConstructFields (c, field, constrCtx, flags)
168
- mergeInitStatus ( result , status)
169
-
169
+ let (subSt, subDf) = semConstructFields (c, field, constrCtx, flags)
170
+ result . status. mergeInitStatus subSt
171
+ result .defaults. add subDf
170
172
of nkRecCase:
171
173
template fieldsPresentInBranch (branchIdx: int ): string =
172
174
let branch = n[branchIdx]
@@ -184,17 +186,18 @@ proc semConstructFields(c: PContext, n: PNode,
184
186
185
187
for i in 1 ..< n.len:
186
188
let innerRecords = n[i][^ 1 ]
187
- let status = semConstructFields (c, innerRecords, constrCtx, flags)
189
+ let ( status, defaults) = semConstructFields (c, innerRecords, constrCtx, flags)
188
190
if status notin {initNone, initUnknown}:
189
- mergeInitStatus (result , status)
191
+ result .status.mergeInitStatus status
192
+ result .defaults.add defaults
190
193
if selectedBranch != - 1 :
191
194
let prevFields = fieldsPresentInBranch (selectedBranch)
192
195
let currentFields = fieldsPresentInBranch (i)
193
196
localError (c.config, constrCtx.initExpr.info,
194
197
(" The fields '$1' and '$2' cannot be initialized together, " &
195
198
" because they are from conflicting branches in the case object." ) %
196
199
[prevFields, currentFields])
197
- result = initConflict
200
+ result .status = initConflict
198
201
else :
199
202
selectedBranch = i
200
203
@@ -206,7 +209,7 @@ proc semConstructFields(c: PContext, n: PNode,
206
209
(" cannot prove that it's safe to initialize $1 with " &
207
210
" the runtime value for the discriminator '$2' " ) %
208
211
[fields, discriminator.sym.name.s])
209
- mergeInitStatus (result , initNone)
212
+ mergeInitStatus (result .status , initNone)
210
213
211
214
template wrongBranchError (i) =
212
215
if c.inUncheckedAssignSection == 0 :
@@ -291,11 +294,11 @@ proc semConstructFields(c: PContext, n: PNode,
291
294
292
295
# When a branch is selected with a partial match, some of the fields
293
296
# that were not initialized may be mandatory. We must check for this:
294
- if result == initPartial:
297
+ if result .status == initPartial:
295
298
collectMissingFields branchNode
296
299
297
300
else :
298
- result = initNone
301
+ result .status = initNone
299
302
let discriminatorVal = semConstrField (c, flags + {efPreferStatic},
300
303
discriminator.sym,
301
304
constrCtx.initExpr)
@@ -308,7 +311,7 @@ proc semConstructFields(c: PContext, n: PNode,
308
311
let matchedBranch = n.pickCaseBranch defaultValue
309
312
collectMissingFields matchedBranch
310
313
else :
311
- result = initPartial
314
+ result .status = initPartial
312
315
if discriminatorVal.kind == nkIntLit:
313
316
# When the discriminator is a compile-time value, we also know
314
317
# which branch will be selected:
@@ -318,23 +321,28 @@ proc semConstructFields(c: PContext, n: PNode,
318
321
# All bets are off. If any of the branches has a mandatory
319
322
# fields we must produce an error:
320
323
for i in 1 ..< n.len: collectMissingFields n[i]
321
-
322
324
of nkSym:
323
325
let field = n.sym
324
326
let e = semConstrField (c, flags, field, constrCtx.initExpr)
325
- result = if e != nil : initFull else : initNone
326
-
327
+ if e != nil :
328
+ result .status = initFull
329
+ elif field.ast != nil :
330
+ result .status = initUnknown
331
+ result .defaults.add newTree (nkExprColonExpr, n, field.ast)
332
+ else :
333
+ result .status = initNone
327
334
else :
328
335
internalAssert c.config, false
329
336
330
337
proc semConstructTypeAux (c: PContext ,
331
338
constrCtx: var ObjConstrContext ,
332
- flags: TExprFlags ): InitStatus =
333
- result = initUnknown
339
+ flags: TExprFlags ): tuple [status: InitStatus , defaults: seq [ PNode ]] =
340
+ result .status = initUnknown
334
341
var t = constrCtx.typ
335
342
while true :
336
- let status = semConstructFields (c, t.n, constrCtx, flags)
337
- mergeInitStatus (result , status)
343
+ let (status, defaults) = semConstructFields (c, t.n, constrCtx, flags)
344
+ result .status.mergeInitStatus status
345
+ result .defaults.add defaults
338
346
if status in {initPartial, initNone, initUnknown}:
339
347
collectMissingFields c, t.n, constrCtx
340
348
let base = t[0 ]
@@ -378,7 +386,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
378
386
proc semObjConstr (c: PContext , n: PNode , flags: TExprFlags ): PNode =
379
387
var t = semTypeNode (c, n[0 ], nil )
380
388
result = newNodeIT (nkObjConstr, n.info, t)
381
- for child in n: result .add child
389
+ result .add newNodeIT (nkType, n.info, t) # This will contain the default values to be added in transf
390
+ for i in 1 ..< n.len:
391
+ result .add n[i]
382
392
383
393
if t == nil :
384
394
return localErrorNode (c, result , " object constructor needs an object type" )
@@ -399,7 +409,8 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
399
409
# field (if this is a case object, initialized fields in two different
400
410
# branches will be reported as an error):
401
411
var constrCtx = initConstrContext (t, result )
402
- let initResult = semConstructTypeAux (c, constrCtx, flags)
412
+ let (initResult, defaults) = semConstructTypeAux (c, constrCtx, flags)
413
+ result [0 ].sons.add defaults
403
414
var hasError = false # needed to split error detect/report for better msgs
404
415
405
416
# It's possible that the object was not fully initialized while
0 commit comments