Skip to content

Commit ad67b71

Browse files
committed
fresh start
1 parent 8bfc396 commit ad67b71

10 files changed

+614
-40
lines changed

compiler/ast.nim

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ type
502502
nfLastRead # this node is a last read
503503
nfFirstWrite# this node is a first write
504504
nfHasComment # node has a comment
505+
nfUseDefaultField
505506

506507
TNodeFlags* = set[TNodeFlag]
507508
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 45)
@@ -1453,6 +1454,17 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
14531454
result.intVal = intVal
14541455
result.typ = typ
14551456

1457+
proc newFloatTypeNode*(floatVal: BiggestFloat, typ: PType): PNode =
1458+
let kind = skipTypes(typ, abstractVarRange).kind
1459+
case kind
1460+
of tyFloat32:
1461+
result = newNode(nkFloat32Lit)
1462+
of tyFloat64, tyFloat:
1463+
result = newNode(nkFloatLit)
1464+
else: doAssert false, $kind
1465+
result.floatVal = floatVal
1466+
result.typ = typ
1467+
14561468
proc newIntTypeNode*(intVal: Int128, typ: PType): PNode =
14571469
# XXX: introduce range check
14581470
newIntTypeNode(castToInt64(intVal), typ)

compiler/parser.nim

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,11 +1963,7 @@ proc parseObjectCase(p: var Parser): PNode =
19631963
#| | IND{=} objectBranches)
19641964
result = newNodeP(nkRecCase, p)
19651965
getTokNoInd(p)
1966-
var a = newNodeP(nkIdentDefs, p)
1967-
a.add(identWithPragma(p))
1968-
eat(p, tkColon)
1969-
a.add(parseTypeDesc(p))
1970-
a.add(p.emptyNode)
1966+
var a = parseIdentColonEquals(p, {withPragma})
19711967
result.add(a)
19721968
if p.tok.tokType == tkColon: getTok(p)
19731969
flexComment(p, result)

compiler/semexprs.nim

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -897,8 +897,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
897897
rawAddSon(typ, result.typ)
898898
result.typ = typ
899899

900-
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
901-
902900
proc resolveIndirectCall(c: PContext; n, nOrig: PNode;
903901
t: PType): TCandidate =
904902
initCandidate(c, result, t)
@@ -2380,6 +2378,16 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
23802378
of mSizeOf:
23812379
markUsed(c, n.info, s)
23822380
result = semSizeof(c, setMs(n, s))
2381+
of mDefault:
2382+
result = semDirectOp(c, n, flags)
2383+
let typ = result[^1].typ.skipTypes({tyTypeDesc})
2384+
if typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject:
2385+
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[^1].info, typ))
2386+
asgnExpr.typ = typ
2387+
var hasDefault: bool
2388+
asgnExpr.sons.add defaultFieldsForTheUninitialized(c.graph, typ.skipTypes({tyGenericInst, tyAlias, tySink}).n, hasDefault)
2389+
if hasDefault:
2390+
result = semObjConstr(c, asgnExpr, flags)
23832391
else:
23842392
result = semDirectOp(c, n, flags)
23852393

compiler/semmagic.nim

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
# This include file implements the semantic checking for magics.
1111
# included from sem.nim
1212

13+
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
14+
1315
proc semAddrArg(c: PContext; n: PNode): PNode =
1416
let x = semExprWithType(c, n)
1517
if x.kind == nkSym:
@@ -454,6 +456,95 @@ proc semPrivateAccess(c: PContext, n: PNode): PNode =
454456
c.currentScope.allowPrivateAccess.add t.sym
455457
result = newNodeIT(nkEmpty, n.info, getSysType(c.graph, n.info, tyVoid))
456458

459+
460+
# import nimsets
461+
462+
463+
464+
# proc caseBranchMatchesExpr2(branch, matched: PNode): bool =
465+
# for i in 0 ..< branch.len-1:
466+
# if branch[i].kind == nkRange:
467+
# if overlap(branch[i], matched): return true
468+
# elif exprStructuralEquivalent(branch[i], matched):
469+
# return true
470+
471+
# proc pickCaseBranch2(caseExpr, matched: PNode): int =
472+
# let endsWithElse = caseExpr[^1].kind == nkElse
473+
# for i in 1..<caseExpr.len - endsWithElse.int:
474+
# if caseExpr[i].caseBranchMatchesExpr2(matched):
475+
# return i
476+
# if endsWithElse:
477+
# return caseExpr.len - 1
478+
479+
# proc defaultFieldsForTheUninitialized2*(c: PContext, recNode: PNode, hasDefault: var bool): seq[PNode] =
480+
# case recNode.kind
481+
# of nkRecList:
482+
# for field in recNode:
483+
# result.add defaultFieldsForTheUninitialized2(c, field, hasDefault)
484+
# of nkRecCase:
485+
# let discriminator = recNode[0]
486+
# var selectedBranch: int
487+
# let defaultValue = discriminator.sym.ast
488+
# if defaultValue == nil:
489+
# # None of the branches were explicitly selected by the user and no value
490+
# # was given to the discrimator. We can assume that it will be initialized
491+
# # to zero and this will select a particular branch as a result:
492+
# selectedBranch = recNode.pickCaseBranch2 newIntNode(nkIntLit#[c.graph]#, 0)
493+
# else: # Try to use default value
494+
# selectedBranch = recNode.pickCaseBranch2 defaultValue
495+
# result.add newTree(nkExprColonExpr, discriminator, defaultValue)
496+
# result.add defaultFieldsForTheUninitialized2(c, recNode[selectedBranch][^1], hasDefault)
497+
# of nkSym:
498+
# let field = recNode.sym
499+
# let recType = recNode.typ.skipTypes({tyGenericInst, tyAlias, tySink})
500+
# if field.ast != nil: #Try to use default value
501+
# result.add newTree(nkExprColonExpr, recNode, field.ast)
502+
# hasDefault = true
503+
# elif recType.kind == tyObject:
504+
# var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, recNode.info, recNode.typ))
505+
# asgnExpr.typ = recNode.typ
506+
# asgnExpr.flags.incl nfUseDefaultField
507+
# asgnExpr.sons.add defaultFieldsForTheUninitialized2(c, recType.n, hasDefault)
508+
# result.add newTree(nkExprColonExpr, recNode, asgnExpr)
509+
# elif recType.kind == tyArray and recType[1].skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject:
510+
# let defaults = defaultFieldsForTheUninitialized2(c, recType[1].skipTypes({tyGenericInst, tyAlias, tySink}).n, hasDefault)
511+
# var objExpr = newTree(nkObjConstr, newNodeIT(nkType, recNode.info, recType[1]))
512+
# objExpr.typ = recType[1].skipTypes({tyGenericInst, tyAlias, tySink})
513+
# objExpr.sons.add defaults # todo create clean?
514+
515+
# let node = newNode(nkIntLit)
516+
# node.intVal = toInt(lengthOrd(c.graph.config, recType))
517+
# var asgnExpr = newTree(nkCall, newSymNode(getSysSym(c.graph, recNode.info, "newDefaultArray"), recNode.info),
518+
# # var asgnExpr = newTree(nkCall, newSymNode(getCompilerProc(c.graph, "newDefaultArray")),
519+
# node,
520+
# objExpr
521+
# )
522+
# asgnExpr.typ = recNode.typ
523+
# asgnExpr.flags.incl nfUseDefaultField
524+
525+
# # asgnExpr.sons.setLen(toInt(lengthOrd(c, recType)))
526+
# # for i in 0..<asgnExpr.sons.len:
527+
# # asgnExpr[i] = objExpr
528+
# let asgnExpr2 = semExprWithType(c, asgnExpr)
529+
# result.add newTree(nkExprColonExpr, recNode, asgnExpr2)
530+
531+
# elif recType.kind == tyTuple:
532+
# # doAssert false
533+
# discard
534+
# elif recType.kind in {tyInt..tyInt64, tyUInt..tyUInt64}:
535+
# let asgnExpr = newIntTypeNode(int64(0), recType)
536+
# asgnExpr.flags.incl nfUseDefaultField
537+
# result.add newTree(nkExprColonExpr, recNode,
538+
# asgnExpr)
539+
# elif recType.kind in tyFloat..tyFloat64:
540+
# let asgnExpr = newFloatTypeNode(BiggestFloat(0.0), recType)
541+
# asgnExpr.flags.incl nfUseDefaultField
542+
# result.add newTree(nkExprColonExpr, recNode,
543+
# asgnExpr)
544+
545+
# else:
546+
# assert false
547+
457548
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
458549
flags: TExprFlags): PNode =
459550
## This is the preferred code point to implement magics.
@@ -512,6 +603,23 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
512603
result = n
513604
else:
514605
result = plugin(c, n)
606+
of mNew:
607+
result = n
608+
let typ = result[^1].typ
609+
if typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyRef and typ.skipTypes({tyGenericInst, tyAlias, tySink})[0].kind == tyObject:
610+
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[^1].info, typ))
611+
asgnExpr.typ = typ
612+
var hasDefault: bool
613+
var t = typ.skipTypes({tyGenericInst, tyAlias, tySink})[0]
614+
while true:
615+
asgnExpr.sons.add defaultFieldsForTheUninitialized(c.graph, t.n, hasDefault)
616+
let base = t[0]
617+
if base == nil:
618+
break
619+
t = skipTypes(base, skipPtrs)
620+
621+
if hasDefault: # todo apply default
622+
result = newTree(nkAsgn, result[^1], asgnExpr)
515623
of mNewFinalize:
516624
# Make sure the finalizer procedure refers to a procedure
517625
if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}:

compiler/semobjconstr.nim

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ type
2929
initNone # None of the fields have been initialized
3030
initConflict # Fields from different branches have been initialized
3131

32+
33+
proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
34+
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]]
35+
3236
proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
3337
case newStatus
3438
of initConflict:
@@ -72,7 +76,9 @@ proc semConstrField(c: PContext, flags: TExprFlags,
7276
let assignment = locateFieldInInitExpr(c, field, initExpr)
7377
if assignment != nil:
7478
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):
7682
localError(c.config, initExpr.info,
7783
"the field '$1' is not accessible." % [field.name.s])
7884
return
@@ -155,18 +161,14 @@ proc collectMissingFields(c: PContext, fieldsRecList: PNode,
155161
if assignment == nil:
156162
constrCtx.missingFields.add r.sym
157163

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]] =
164166
case n.kind
165167
of nkRecList:
166168
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
170172
of nkRecCase:
171173
template fieldsPresentInBranch(branchIdx: int): string =
172174
let branch = n[branchIdx]
@@ -184,17 +186,17 @@ proc semConstructFields(c: PContext, n: PNode,
184186

185187
for i in 1..<n.len:
186188
let innerRecords = n[i][^1]
187-
let status = semConstructFields(c, innerRecords, constrCtx, flags)
189+
let (status, _) = semConstructFields(c, innerRecords, constrCtx, flags) # todo
188190
if status notin {initNone, initUnknown}:
189-
mergeInitStatus(result, status)
191+
result.status.mergeInitStatus status
190192
if selectedBranch != -1:
191193
let prevFields = fieldsPresentInBranch(selectedBranch)
192194
let currentFields = fieldsPresentInBranch(i)
193195
localError(c.config, constrCtx.initExpr.info,
194196
("The fields '$1' and '$2' cannot be initialized together, " &
195197
"because they are from conflicting branches in the case object.") %
196198
[prevFields, currentFields])
197-
result = initConflict
199+
result.status = initConflict
198200
else:
199201
selectedBranch = i
200202

@@ -206,7 +208,7 @@ proc semConstructFields(c: PContext, n: PNode,
206208
("cannot prove that it's safe to initialize $1 with " &
207209
"the runtime value for the discriminator '$2' ") %
208210
[fields, discriminator.sym.name.s])
209-
mergeInitStatus(result, initNone)
211+
mergeInitStatus(result.status, initNone)
210212

211213
template wrongBranchError(i) =
212214
if c.inUncheckedAssignSection == 0:
@@ -289,13 +291,16 @@ proc semConstructFields(c: PContext, n: PNode,
289291
else:
290292
wrongBranchError(failedBranch)
291293

294+
let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
295+
result.defaults.add defaults
296+
292297
# When a branch is selected with a partial match, some of the fields
293298
# that were not initialized may be mandatory. We must check for this:
294-
if result == initPartial:
299+
if result.status == initPartial:
295300
collectMissingFields branchNode
296301

297302
else:
298-
result = initNone
303+
result.status = initNone
299304
let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
300305
discriminator.sym,
301306
constrCtx.initExpr)
@@ -308,33 +313,41 @@ proc semConstructFields(c: PContext, n: PNode,
308313
let matchedBranch = n.pickCaseBranch defaultValue
309314
collectMissingFields matchedBranch
310315
else:
311-
result = initPartial
316+
result.status = initPartial
312317
if discriminatorVal.kind == nkIntLit:
313318
# When the discriminator is a compile-time value, we also know
314319
# which branch will be selected:
315320
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
317325
else:
318326
# All bets are off. If any of the branches has a mandatory
319327
# fields we must produce an error:
320328
for i in 1..<n.len: collectMissingFields n[i]
321-
322329
of nkSym:
323330
let field = n.sym
324331
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
327339
else:
328340
internalAssert c.config, false
329341

330342
proc semConstructTypeAux(c: PContext,
331343
constrCtx: var ObjConstrContext,
332-
flags: TExprFlags): InitStatus =
333-
result = initUnknown
344+
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
345+
result.status = initUnknown
334346
var t = constrCtx.typ
335347
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
338351
if status in {initPartial, initNone, initUnknown}:
339352
collectMissingFields c, t.n, constrCtx
340353
let base = t[0]
@@ -378,7 +391,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
378391
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
379392
var t = semTypeNode(c, n[0], nil)
380393
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]
382397

383398
if t == nil:
384399
return localErrorNode(c, result, "object constructor needs an object type")
@@ -399,7 +414,8 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
399414
# field (if this is a case object, initialized fields in two different
400415
# branches will be reported as an error):
401416
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
403419
var hasError = false # needed to split error detect/report for better msgs
404420

405421
# It's possible that the object was not fully initialized while

compiler/semstmts.nim

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,15 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
594594
var typFlags: TTypeAllowedFlags
595595

596596
var def: PNode = c.graph.emptyNode
597+
if a[^1].kind == nkEmpty and symkind == skVar and a[^2].typ != nil:
598+
let m = copyTree(a[0])
599+
# var v = semIdentDef(c, m, symkind, false)
600+
# if {sfThread, sfNoInit} * v.flags != {}: # todo var m1, m2 {threadvar}
601+
# discard # todo init threadvar properly
602+
# else:
603+
let field = defaultNodeField(c.graph, a[^2])
604+
if field != nil:
605+
a[^1] = field
597606
if a[^1].kind != nkEmpty:
598607
def = semExprWithType(c, a[^1], {})
599608

@@ -662,6 +671,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
662671
addToVarSection(c, result, n, a)
663672
continue
664673
var v = semIdentDef(c, a[j], symkind, false)
674+
if {sfThread, sfNoInit} * v.flags != {}:
675+
a[^1] = c.graph.emptyNode
676+
def = c.graph.emptyNode
665677
styleCheckDef(c.config, v)
666678
onDef(a[j].info, v)
667679
if sfGenSym notin v.flags:

0 commit comments

Comments
 (0)