@@ -140,22 +140,16 @@ proc caseBranchMatchesExpr(branch, matched: PNode): bool =
140
140
elif exprStructuralEquivalent (branch[i], matched):
141
141
return true
142
142
143
- proc pickCaseBranches (caseExpr, matched: PNode ): seq [PNode ] =
143
+ proc pickCaseBranches (caseExpr, matched: PNode ): seq [int ] =
144
144
let endsWithElse = caseExpr[^ 1 ].kind == nkElse
145
145
for i in 1 ..< caseExpr.len - int (endsWithElse):
146
146
if caseExpr[i].caseBranchMatchesExpr (matched):
147
- result .add caseExpr[i]
147
+ result .add i
148
148
if endsWithElse and result .len == 0 :
149
- result .add caseExpr[ ^ 1 ]
149
+ result .add caseExpr.len - 1
150
150
151
- proc pickCaseBranch (caseExpr, matched: PNode ): PNode =
152
- # XXX: Perhaps this proc already exists somewhere
153
- let endsWithElse = caseExpr[^ 1 ].kind == nkElse
154
- for i in 1 ..< caseExpr.len - int (endsWithElse):
155
- if caseExpr[i].caseBranchMatchesExpr (matched):
156
- return caseExpr[i]
157
- if endsWithElse:
158
- return caseExpr[^ 1 ]
151
+ proc pickCaseBranch (caseExpr, matched: PNode ): int =
152
+ pickCaseBranches (caseExpr, matched)[0 ]
159
153
160
154
iterator directFieldsInRecList (recList: PNode ): PNode =
161
155
# XXX: We can remove this case by making all nkOfBranch nodes
@@ -214,80 +208,77 @@ proc semConstructFields(c: PContext, recNode: PNode,
214
208
215
209
let discriminator = recNode[0 ]
216
210
internalAssert c.config, discriminator.kind == nkSym
217
- var selectedBranch = - 1
218
-
219
- for i in 1 ..< recNode.len:
220
- let innerRecords = recNode[i][^ 1 ]
221
- let status = semConstructFields (c, innerRecords, initExpr, flags)
222
- if status notin {initNone, initUnknown}:
223
- mergeInitStatus (result , status)
224
- if selectedBranch != - 1 :
225
- let prevFields = fieldsPresentInBranch (selectedBranch)
226
- let currentFields = fieldsPresentInBranch (i)
227
- localError (c.config, initExpr.info,
228
- (" The fields '$1' and '$2' cannot be initialized together, " &
229
- " because they are from conflicting branches in the case object." ) %
230
- [prevFields, currentFields])
231
- result = initConflict
232
- else :
233
- selectedBranch = i
234
-
235
- if selectedBranch != - 1 :
236
- template badDiscriminatorError =
237
- let fields = fieldsPresentInBranch (selectedBranch)
238
- localError (c.config, initExpr.info,
239
- (" cannot prove that it's safe to initialize $1 with " &
240
- " the runtime value for the discriminator '$2' " ) %
241
- [fields, discriminator.sym.name.s])
242
- mergeInitStatus (result , initNone)
243
-
244
- template wrongBranchError (i) =
245
- let fields = fieldsPresentInBranch (i)
246
- localError (c.config, initExpr.info,
247
- " a case selecting discriminator '$1' with value '$2' " &
248
- " appears in the object construction, but the field(s) $3 " &
249
- " are in conflict with this value." ,
250
- [discriminator.sym.name.s, discriminatorVal.renderTree, fields])
251
-
252
- template valuesInConflictError (valsDiff) =
253
- localError (c.config, discriminatorVal.info, (" possible values " &
254
- " $2are in conflict with discriminator values for " &
255
- " selected object branch $1." ) % [$ selectedBranch,
256
- formatUnsafeBranchVals (recNode[0 ].typ, valsDiff)])
257
-
258
- let branchNode = recNode[selectedBranch]
259
- let flags = flags* {efAllowDestructor} + {efPreferStatic,
260
- efPreferNilResult}
261
- var discriminatorVal = semConstrField (c, flags,
262
- discriminator.sym, initExpr)
263
- if discriminatorVal == nil : # Try to use default value
264
- discriminatorVal = discriminator.sym.ast
265
-
266
- if discriminatorVal != nil :
267
- discriminatorVal = discriminatorVal.skipHidden
268
- if discriminatorVal.kind notin nkLiterals and (
269
- not isOrdinalType (discriminatorVal.typ, true ) or
270
- lengthOrd (c.config, discriminatorVal.typ) > MaxSetElements or
271
- lengthOrd (c.config, recNode[0 ].typ) > MaxSetElements ):
272
- localError (c.config, discriminatorVal.info,
273
- " branch initialization with a runtime discriminator only " &
274
- " supports ordinal types with 2^16 elements or less." )
275
211
276
- if discriminatorVal == nil :
277
- badDiscriminatorError ()
212
+ # for i in 1 ..< recNode.len:
213
+ # let innerRecords = recNode[i][^1]
214
+ # let status = semConstructFields(c, innerRecords, initExpr, flags)
215
+ # if status notin {initNone, initUnknown}:
216
+ # mergeInitStatus(result, status)
217
+ # if selectedBranch != -1:
218
+ # let prevFields = fieldsPresentInBranch(selectedBranch)
219
+ # let currentFields = fieldsPresentInBranch(i)
220
+ # localError(c.config, initExpr.info,
221
+ # ("The fields '$1' and '$2' cannot be initialized together, " &
222
+ # "because they are from conflicting branches in the case object.") %
223
+ # [prevFields, currentFields])
224
+ # result = initConflict
225
+ # else:
226
+ # selectedBranch = i
227
+
228
+
229
+ # template wrongBranchError(i) =
230
+ # let fields = fieldsPresentInBranch(i)
231
+ # localError(c.config, initExpr.info,
232
+ # "a case selecting discriminator '$1' with value '$2' " &
233
+ # "appears in the object construction, but the field(s) $3 " &
234
+ # "are in conflict with this value.",
235
+ # [discriminator.sym.name.s, discriminatorVal.renderTree, fields])
236
+ # let flags = flags*{efAllowDestructor} + {efPreferStatic, efPreferNilResult}
237
+ # var discriminatorVal = semConstrField(c, flags, discriminator.sym, initExpr)
238
+ template valuesInConflictError (valsDiff) =
239
+ localError (c.config, discriminatorVal.info, (" possible values " &
240
+ " $2are in conflict with discriminator values for " &
241
+ " selected object branch $1." ) % [$ selectedBranch,
242
+ formatUnsafeBranchVals (recNode[0 ].typ, valsDiff)])
243
+
244
+
245
+ var selectedBranch: int
246
+ let defaultValue = discriminator.sym.ast
247
+
248
+ var discriminatorVal = semConstrField (c, flags + {efPreferStatic}, discriminator.sym, initExpr)
249
+
250
+ if discriminatorVal == nil and defaultValue == nil :
251
+ # None of the branches were explicitly selected by the user and no value
252
+ # was given to the discrimator. We can assume that it will be initialized
253
+ # to zero and this will select a particular branch as a result:
254
+ selectedBranch = recNode.pickCaseBranch newIntLit (c.graph, initExpr.info, 0 )
255
+ checkMissingFields recNode[selectedBranch], true
256
+ elif defaultValue != nil :
257
+ # Try to use default value
258
+ discriminatorVal = defaultValue
259
+ selectedBranch = recNode.pickCaseBranch defaultValue
260
+ checkMissingFields recNode[selectedBranch], true
261
+ else :
262
+ discriminatorVal = discriminatorVal.skipHidden
263
+ if discriminatorVal.kind == nkIntLit:
264
+ # Discriminator is a compile-time value, we know which branch will be selected
265
+ selectedBranch = recNode.pickCaseBranch discriminatorVal
266
+ if selectedBranch != 0 : checkMissingFields recNode[selectedBranch], true
267
+ elif discriminatorVal.typ.kind == tyRange:
268
+ let selectedBranches = recNode.pickCaseBranches discriminatorVal.typ.n
269
+ for b in selectedBranches:
270
+ checkMissingFields recNode[b], selectedBranches.len == 0
278
271
elif discriminatorVal.kind == nkSym:
279
272
let (ctorCase, ctorIdx) = findUsefulCaseContext (c, discriminatorVal)
280
273
if ctorCase == nil :
281
- if discriminatorVal.typ.kind == tyRange:
282
- let rangeVals = rangeTypVals (discriminatorVal.typ)
283
- let recBranchVals = branchVals (c, recNode, selectedBranch, false )
284
- let diff = rangeVals - recBranchVals
285
- if diff.len != 0 :
286
- valuesInConflictError (diff)
287
- else :
288
- badDiscriminatorError ()
274
+ let fields = fieldsPresentInBranch (selectedBranch)
275
+ localError (c.config, initExpr.info,
276
+ (" cannot prove that it's safe to initialize $1 with " &
277
+ " the runtime value for the discriminator '$2' " ) %
278
+ [fields, discriminator.sym.name.s])
279
+ mergeInitStatus (result , initNone)
289
280
elif discriminatorVal.sym.kind notin {skLet, skParam} or
290
- discriminatorVal.sym.typ.kind == tyVar:
281
+ discriminatorVal.sym.typ.kind == tyVar:
291
282
localError (c.config, discriminatorVal.info,
292
283
" runtime discriminator must be immutable if branch fields are " &
293
284
" initialized, a 'let' binding is required." )
@@ -303,65 +294,11 @@ proc semConstructFields(c: PContext, recNode: PNode,
303
294
if branchValsDiff.len != 0 :
304
295
valuesInConflictError (branchValsDiff)
305
296
else :
306
- var failedBranch = - 1
307
- if branchNode.kind != nkElse:
308
- if not branchNode.caseBranchMatchesExpr (discriminatorVal):
309
- failedBranch = selectedBranch
310
- else :
311
- # With an else clause, check that all other branches don't match:
312
- for i in 1 .. (recNode.len - 2 ):
313
- if recNode[i].caseBranchMatchesExpr (discriminatorVal):
314
- failedBranch = i
315
- break
316
- if failedBranch != - 1 :
317
- if discriminatorVal.typ.kind == tyRange:
318
- let rangeVals = rangeTypVals (discriminatorVal.typ)
319
- let recBranchVals = branchVals (c, recNode, selectedBranch, false )
320
- let diff = rangeVals - recBranchVals
321
- if diff.len != 0 :
322
- valuesInConflictError (diff)
323
- else :
324
- wrongBranchError (failedBranch)
325
-
326
- # When a branch is selected with a partial match, some of the fields
327
- # that were not initialized may be mandatory. We must check for this:
328
- if result == initPartial:
329
- checkMissingFields branchNode, true
330
-
331
- else :
332
- result = initNone
333
- var discriminatorVal = semConstrField (c, flags + {efPreferStatic}, discriminator.sym, initExpr)
334
-
335
- var matchedBranch: PNode
336
-
337
- if discriminatorVal == nil : # Try to use default value
338
- discriminatorVal = discriminator.sym.ast
339
-
340
- if discriminatorVal == nil :
341
- # None of the branches were explicitly selected by the user and no
342
- # value was given to the discrimator. We can assume that it will be
343
- # initialized to zero and this will select a particular branch as
344
- # a result:
345
- matchedBranch = recNode.pickCaseBranch newIntLit (c.graph, initExpr.info, 0 )
346
- checkMissingFields matchedBranch, true
347
- else :
348
- result = initPartial
349
- discriminatorVal = discriminatorVal.skipHidden
350
- debug discriminatorVal
351
- if discriminatorVal.kind == nkIntLit: # or discriminatorVal.typ.kind == tyRange:
352
- # When the discriminator is a compile-time value, we also know
353
- # which branch will be selected:
354
- matchedBranch = recNode.pickCaseBranch discriminatorVal
355
- if matchedBranch != nil : checkMissingFields matchedBranch, true
356
- elif discriminatorVal.typ.kind == tyRange:
357
- let matchedBranches = recNode.pickCaseBranches discriminatorVal.typ.n
358
- for m in matchedBranches:
359
- checkMissingFields m, matchedBranches.len == 0
360
- else :
361
- # All bets are off. If any of the branches has a mandatory
362
- # fields we must produce an error:
363
- for i in 1 ..< recNode.len: checkMissingFields recNode[i], false
297
+ # All bets are off. If any of the branches has a mandatory
298
+ # fields we must produce an error:
299
+ for i in 1 ..< recNode.len: checkMissingFields recNode[i], false
364
300
301
+ discard semConstructFields (c, recNode[selectedBranch][^ 1 ], initExpr, flags)
365
302
of nkSym:
366
303
let field = recNode.sym
367
304
let e = semConstrField (c, flags, field, initExpr)
@@ -428,20 +365,20 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
428
365
# Since we were traversing the object fields, it's possible that
429
366
# not all of the fields specified in the constructor was visited.
430
367
# We'll check for such fields here:
431
- for i in 1 ..< reslen:
432
- let field = result [i]
433
- if nfSem notin field.flags:
434
- if field.kind != nkExprColonExpr:
435
- invalidObjConstr (c, field)
436
- continue
437
- let id = considerQuotedIdent (c, field[0 ])
438
- # This node was not processed. There are two possible reasons:
439
- # 1) It was shadowed by a field with the same name on the left
440
- for j in 1 ..< i:
441
- let prevId = considerQuotedIdent (c, result [j][0 ])
442
- if prevId.id == id.id:
443
- localError (c.config, field.info, errFieldInitTwice % id.s)
444
- return
445
- # 2) No such field exists in the constructed type
446
- localError (c.config, field.info, errUndeclaredFieldX % id.s)
447
- return
368
+ # for i in 1..<reslen:
369
+ # let field = result[i]
370
+ # if nfSem notin field.flags:
371
+ # if field.kind != nkExprColonExpr:
372
+ # invalidObjConstr(c, field)
373
+ # continue
374
+ # let id = considerQuotedIdent(c, field[0])
375
+ # # This node was not processed. There are two possible reasons:
376
+ # # 1) It was shadowed by a field with the same name on the left
377
+ # for j in 1 ..< i:
378
+ # let prevId = considerQuotedIdent(c, result[j][0])
379
+ # if prevId.id == id.id:
380
+ # localError(c.config, field.info, errFieldInitTwice % id.s)
381
+ # return
382
+ # # 2) No such field exists in the constructed type
383
+ # localError(c.config, field.info, errUndeclaredFieldX % id.s)
384
+ # return
0 commit comments