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,17 @@ 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, _) = semConstructFields (c, innerRecords, constrCtx, flags) # todo
188
190
if status notin {initNone, initUnknown}:
189
- mergeInitStatus ( result , status)
191
+ result .status. mergeInitStatus status
190
192
if selectedBranch != - 1 :
191
193
let prevFields = fieldsPresentInBranch (selectedBranch)
192
194
let currentFields = fieldsPresentInBranch (i)
193
195
localError (c.config, constrCtx.initExpr.info,
194
196
(" The fields '$1' and '$2' cannot be initialized together, " &
195
197
" because they are from conflicting branches in the case object." ) %
196
198
[prevFields, currentFields])
197
- result = initConflict
199
+ result .status = initConflict
198
200
else :
199
201
selectedBranch = i
200
202
@@ -206,7 +208,7 @@ proc semConstructFields(c: PContext, n: PNode,
206
208
(" cannot prove that it's safe to initialize $1 with " &
207
209
" the runtime value for the discriminator '$2' " ) %
208
210
[fields, discriminator.sym.name.s])
209
- mergeInitStatus (result , initNone)
211
+ mergeInitStatus (result .status , initNone)
210
212
211
213
template wrongBranchError (i) =
212
214
if c.inUncheckedAssignSection == 0 :
@@ -289,13 +291,16 @@ proc semConstructFields(c: PContext, n: PNode,
289
291
else :
290
292
wrongBranchError (failedBranch)
291
293
294
+ let (_, defaults) = semConstructFields (c, branchNode[^ 1 ], constrCtx, flags)
295
+ result .defaults.add defaults
296
+
292
297
# When a branch is selected with a partial match, some of the fields
293
298
# that were not initialized may be mandatory. We must check for this:
294
- if result == initPartial:
299
+ if result .status == initPartial:
295
300
collectMissingFields branchNode
296
301
297
302
else :
298
- result = initNone
303
+ result .status = initNone
299
304
let discriminatorVal = semConstrField (c, flags + {efPreferStatic},
300
305
discriminator.sym,
301
306
constrCtx.initExpr)
@@ -308,33 +313,41 @@ proc semConstructFields(c: PContext, n: PNode,
308
313
let matchedBranch = n.pickCaseBranch defaultValue
309
314
collectMissingFields matchedBranch
310
315
else :
311
- result = initPartial
316
+ result .status = initPartial
312
317
if discriminatorVal.kind == nkIntLit:
313
318
# When the discriminator is a compile-time value, we also know
314
319
# which branch will be selected:
315
320
let matchedBranch = n.pickCaseBranch discriminatorVal
316
- if matchedBranch != nil : collectMissingFields matchedBranch
321
+ if matchedBranch != nil :
322
+ let (_, defaults) = semConstructFields (c, matchedBranch[^ 1 ], constrCtx, flags)
323
+ result .defaults.add defaults
324
+ collectMissingFields matchedBranch
317
325
else :
318
326
# All bets are off. If any of the branches has a mandatory
319
327
# fields we must produce an error:
320
328
for i in 1 ..< n.len: collectMissingFields n[i]
321
-
322
329
of nkSym:
323
330
let field = n.sym
324
331
let e = semConstrField (c, flags, field, constrCtx.initExpr)
325
- result = if e != nil : initFull else : initNone
326
-
332
+ if e != nil :
333
+ result .status = initFull
334
+ elif field.ast != nil :
335
+ result .status = initUnknown
336
+ result .defaults.add newTree (nkExprColonExpr, n, field.ast)
337
+ else :
338
+ result .status = initNone
327
339
else :
328
340
internalAssert c.config, false
329
341
330
342
proc semConstructTypeAux (c: PContext ,
331
343
constrCtx: var ObjConstrContext ,
332
- flags: TExprFlags ): InitStatus =
333
- result = initUnknown
344
+ flags: TExprFlags ): tuple [status: InitStatus , defaults: seq [ PNode ]] =
345
+ result .status = initUnknown
334
346
var t = constrCtx.typ
335
347
while true :
336
- let status = semConstructFields (c, t.n, constrCtx, flags)
337
- mergeInitStatus (result , status)
348
+ let (status, defaults) = semConstructFields (c, t.n, constrCtx, flags)
349
+ result .status.mergeInitStatus status
350
+ result .defaults.add defaults
338
351
if status in {initPartial, initNone, initUnknown}:
339
352
collectMissingFields c, t.n, constrCtx
340
353
let base = t[0 ]
@@ -378,7 +391,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
378
391
proc semObjConstr (c: PContext , n: PNode , flags: TExprFlags ): PNode =
379
392
var t = semTypeNode (c, n[0 ], nil )
380
393
result = newNodeIT (nkObjConstr, n.info, t)
381
- for child in n: result .add child
394
+ result .add newNodeIT (nkType, n.info, t) # This will contain the default values to be added in transf
395
+ for i in 1 ..< n.len:
396
+ result .add n[i]
382
397
383
398
if t == nil :
384
399
return localErrorNode (c, result , " object constructor needs an object type" )
@@ -399,7 +414,8 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
399
414
# field (if this is a case object, initialized fields in two different
400
415
# branches will be reported as an error):
401
416
var constrCtx = initConstrContext (t, result )
402
- let initResult = semConstructTypeAux (c, constrCtx, flags)
417
+ let (initResult, defaults) = semConstructTypeAux (c, constrCtx, flags)
418
+ result [0 ].sons.add defaults
403
419
var hasError = false # needed to split error detect/report for better msgs
404
420
405
421
# It's possible that the object was not fully initialized while
0 commit comments