Skip to content

Commit 0b32c96

Browse files
committed
fix range type
1 parent 8bfc396 commit 0b32c96

File tree

8 files changed

+164
-39
lines changed

8 files changed

+164
-39
lines changed

compiler/ast.nim

+1
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)

compiler/parser.nim

+1-5
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

+8-2
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,14 @@ 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(abstractInst).kind == tyObject:
2385+
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[^1].info, typ))
2386+
asgnExpr.typ = typ
2387+
asgnExpr.sons.add defaultFieldsForTheUninitialized(c.graph.config, typ.skipTypes({tyGenericInst, tyAlias, tySink}).n)
2388+
result = semObjConstr(c, asgnExpr, flags)
23832389
else:
23842390
result = semDirectOp(c, n, flags)
23852391

compiler/semmagic.nim

+10
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:
@@ -512,6 +514,14 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
512514
result = n
513515
else:
514516
result = plugin(c, n)
517+
of mNew:
518+
result = n
519+
let typ = result[^1].typ
520+
if typ.skipTypes(abstractInst).kind == tyRef and typ.skipTypes(abstractInst)[0].kind == tyObject:
521+
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, result[^1].info, typ))
522+
asgnExpr.typ = typ
523+
asgnExpr.sons.add defaultFieldsForTheUninitialized(c.graph.config, typ.skipTypes(abstractInst)[0].n)
524+
result = newTree(nkAsgn, result[^1], semObjConstr(c, asgnExpr, flags))
515525
of mNewFinalize:
516526
# Make sure the finalizer procedure refers to a procedure
517527
if n[^1].kind == nkSym and n[^1].sym.kind notin {skProc, skFunc}:

compiler/semobjconstr.nim

+37-26
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,18 @@ 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, defaults) = semConstructFields(c, innerRecords, constrCtx, flags)
188190
if status notin {initNone, initUnknown}:
189-
mergeInitStatus(result, status)
191+
result.status.mergeInitStatus status
192+
result.defaults.add defaults
190193
if selectedBranch != -1:
191194
let prevFields = fieldsPresentInBranch(selectedBranch)
192195
let currentFields = fieldsPresentInBranch(i)
193196
localError(c.config, constrCtx.initExpr.info,
194197
("The fields '$1' and '$2' cannot be initialized together, " &
195198
"because they are from conflicting branches in the case object.") %
196199
[prevFields, currentFields])
197-
result = initConflict
200+
result.status = initConflict
198201
else:
199202
selectedBranch = i
200203

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

211214
template wrongBranchError(i) =
212215
if c.inUncheckedAssignSection == 0:
@@ -291,11 +294,11 @@ proc semConstructFields(c: PContext, n: PNode,
291294

292295
# When a branch is selected with a partial match, some of the fields
293296
# that were not initialized may be mandatory. We must check for this:
294-
if result == initPartial:
297+
if result.status == initPartial:
295298
collectMissingFields branchNode
296299

297300
else:
298-
result = initNone
301+
result.status = initNone
299302
let discriminatorVal = semConstrField(c, flags + {efPreferStatic},
300303
discriminator.sym,
301304
constrCtx.initExpr)
@@ -308,7 +311,7 @@ proc semConstructFields(c: PContext, n: PNode,
308311
let matchedBranch = n.pickCaseBranch defaultValue
309312
collectMissingFields matchedBranch
310313
else:
311-
result = initPartial
314+
result.status = initPartial
312315
if discriminatorVal.kind == nkIntLit:
313316
# When the discriminator is a compile-time value, we also know
314317
# which branch will be selected:
@@ -318,23 +321,28 @@ proc semConstructFields(c: PContext, n: PNode,
318321
# All bets are off. If any of the branches has a mandatory
319322
# fields we must produce an error:
320323
for i in 1..<n.len: collectMissingFields n[i]
321-
322324
of nkSym:
323325
let field = n.sym
324326
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
327334
else:
328335
internalAssert c.config, false
329336

330337
proc semConstructTypeAux(c: PContext,
331338
constrCtx: var ObjConstrContext,
332-
flags: TExprFlags): InitStatus =
333-
result = initUnknown
339+
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
340+
result.status = initUnknown
334341
var t = constrCtx.typ
335342
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
338346
if status in {initPartial, initNone, initUnknown}:
339347
collectMissingFields c, t.n, constrCtx
340348
let base = t[0]
@@ -378,7 +386,9 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
378386
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
379387
var t = semTypeNode(c, n[0], nil)
380388
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]
382392

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

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

compiler/semstmts.nim

+25
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,31 @@ 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+
var v = semIdentDef(c, a[0], symkind, false)
599+
if {sfThread, sfNoInit} * v.flags != {}: # todo var m1, m2 {threadvar}
600+
discard # todo init threadvar properly
601+
else:
602+
let aTyp = a[^2].typ
603+
if aTyp.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject:
604+
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, a[^2].info, aTyp))
605+
asgnExpr.typ = aTyp
606+
asgnExpr.sons.add defaultFieldsForTheUninitialized(c.graph.config, aTyp.skipTypes({tyGenericInst, tyAlias, tySink}).n)
607+
a[^1] = asgnExpr
608+
elif aTyp.kind == tyArray and aTyp[1].skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject:
609+
var asgnExpr = newNodeI(nkBracket, a[^2].info)
610+
asgnExpr.typ = aTyp
611+
let defaults = defaultFieldsForTheUninitialized(c.graph.config, aTyp[1].skipTypes({tyGenericInst, tyAlias, tySink}).n)
612+
for i in 0..<toInt(lengthOrd(c.config, aTyp)):
613+
var objExpr = newTree(nkObjConstr, newNodeIT(nkType, a[^2].info, aTyp[1]))
614+
objExpr.typ = aTyp[1]
615+
objExpr.sons.add defaults # todo create clean?
616+
asgnExpr.add objExpr
617+
a[^1] = asgnExpr
618+
elif aTyp.kind == tyTuple:
619+
# debug aTyp
620+
discard
621+
597622
if a[^1].kind != nkEmpty:
598623
def = semExprWithType(c, a[^1], {})
599624

compiler/semtypes.nim

+16-5
Original file line numberDiff line numberDiff line change
@@ -777,14 +777,21 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
777777
var a: PNode
778778
if father.kind != nkRecList and n.len >= 4: a = newNodeI(nkRecList, n.info)
779779
else: a = newNodeI(nkEmpty, n.info)
780-
if n[^1].kind != nkEmpty:
781-
localError(c.config, n[^1].info, errInitHereNotAllowed)
782780
var typ: PType
783-
if n[^2].kind == nkEmpty:
781+
var hasDefaultField = n[^1].kind != nkEmpty
782+
if hasDefaultField:
783+
n[^1] = semConstExpr(c, n[^1])
784+
typ = n[^1].typ
785+
propagateToOwner(rectype, typ)
786+
elif n[^2].kind == nkEmpty:
784787
localError(c.config, n.info, errTypeExpected)
785788
typ = errorType(c)
786789
else:
787790
typ = semTypeNode(c, n[^2], nil)
791+
if typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind in {tyRange, tyOrdinal}:
792+
n[^1] = semConstExpr(c, newIntNode(nkIntLit, firstOrd(c.config, typ)))
793+
n[^1].typ = typ
794+
hasDefaultField = true
788795
propagateToOwner(rectype, typ)
789796
var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner
790797
else: rectype.sym
@@ -806,8 +813,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
806813
inc(pos)
807814
if containsOrIncl(check, f.name.id):
808815
localError(c.config, info, "attempt to redefine: '" & f.name.s & "'")
809-
if a.kind == nkEmpty: father.add newSymNode(f)
810-
else: a.add newSymNode(f)
816+
let fSym = newSymNode(f)
817+
if hasDefaultField:
818+
fSym.sym.ast = n[^1]
819+
fSym.sym.ast.flags.incl nfUseDefaultField
820+
if a.kind == nkEmpty: father.add fSym
821+
else: a.add fSym
811822
styleCheckDef(c.config, f)
812823
onDef(f.info, f)
813824
if a.kind != nkEmpty: father.add a

compiler/transf.nim

+66-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type
4646
module: PSym
4747
transCon: PTransCon # top of a TransCon stack
4848
inlining: int # > 0 if we are in inlining context (copy vars)
49-
nestedProcs: int # > 0 if we are in a nested proc
49+
genResult: bool
5050
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
5151
deferDetected, tooEarly: bool
5252
graph: ModuleGraph
@@ -927,6 +927,49 @@ proc commonOptimizations*(g: ModuleGraph; idgen: IdGenerator; c: PSym, n: PNode)
927927
else:
928928
result = n
929929

930+
proc defaultFieldsForTheUninitialized*(c: ConfigRef, recNode: PNode): seq[PNode] =
931+
case recNode.kind
932+
of nkRecList:
933+
for field in recNode:
934+
result.add defaultFieldsForTheUninitialized(c, field)
935+
of nkRecCase:
936+
discard
937+
# let discriminator = recNode[0]
938+
# var selectedBranch: int
939+
# let defaultValue = discriminator.sym.ast
940+
# if defaultValue == nil:
941+
# # None of the branches were explicitly selected by the user and no value
942+
# # was given to the discrimator. We can assume that it will be initialized
943+
# # to zero and this will select a particular branch as a result:
944+
# selectedBranch = recNode.pickCaseBranch newIntNode(nkIntLit#[c.graph]#, 0)
945+
# else: # Try to use default value
946+
# selectedBranch = recNode.pickCaseBranch defaultValue
947+
# result.add newTree(nkExprColonExpr, discriminator, defaultValue)
948+
# result.add defaultFieldsForTheUninitialized(recNode[selectedBranch][^1])
949+
of nkSym:
950+
let field = recNode.sym
951+
if field.ast != nil: #Try to use default value
952+
result.add newTree(nkExprColonExpr, recNode, field.ast)
953+
elif recNode.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject:
954+
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, recNode.info, recNode.typ))
955+
asgnExpr.typ = recNode.typ
956+
asgnExpr.flags.incl nfUseDefaultField
957+
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, recNode.typ.skipTypes({tyGenericInst, tyAlias, tySink}).n)
958+
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
959+
elif recNode.typ.kind == tyArray and recNode.typ[1].skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject:
960+
var asgnExpr = newNodeI(nkBracket, recNode.info)
961+
asgnExpr.typ = recNode.typ
962+
asgnExpr.flags.incl nfUseDefaultField
963+
let defaults = defaultFieldsForTheUninitialized(c, recNode.typ[1].skipTypes({tyGenericInst, tyAlias, tySink}).n)
964+
for i in 0..<toInt(lengthOrd(c, recNode.typ)):
965+
var objExpr = newTree(nkObjConstr, newNodeIT(nkType, recNode.info, recNode.typ[1]))
966+
objExpr.typ = recNode.typ[1]
967+
objExpr.sons.add defaults # todo create clean?
968+
asgnExpr.add objExpr
969+
result.add newTree(nkExprColonExpr, recNode, asgnExpr)
970+
else:
971+
assert false
972+
930973
proc transform(c: PTransf, n: PNode): PNode =
931974
when false:
932975
var oldDeferAnchor: PNode
@@ -935,6 +978,20 @@ proc transform(c: PTransf, n: PNode): PNode =
935978
nkBlockStmt, nkBlockExpr}:
936979
oldDeferAnchor = c.deferAnchor
937980
c.deferAnchor = n
981+
982+
if c.genResult:
983+
c.genResult = false
984+
result = newNodeIT(nkStmtList, n.info, nil)
985+
let toInit = c.getCurrOwner().ast[resultPos]
986+
# todo should be same as var
987+
if toInit.typ != nil and toInit.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyObject:
988+
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, toInit.info, toInit.typ))
989+
asgnExpr.typ = toInit.typ
990+
asgnExpr.sons.add defaultFieldsForTheUninitialized(c.graph.config, toInit.typ.skipTypes({tyGenericInst, tyAlias, tySink}).n)
991+
result.add transform(c, newTree(nkAsgn, toInit, asgnExpr))
992+
result.add transform(c, n)
993+
return result
994+
938995
case n.kind
939996
of nkSym:
940997
result = transformSym(c, n)
@@ -1052,6 +1109,13 @@ proc transform(c: PTransf, n: PNode): PNode =
10521109
result = n
10531110
of nkExceptBranch:
10541111
result = transformExceptBranch(c, n)
1112+
of nkObjConstr:
1113+
result = n
1114+
if result.typ.skipTypes(abstractInst).kind == tyObject or
1115+
result.typ.skipTypes(abstractInst).kind == tyRef and result.typ.skipTypes(abstractInst)[0].kind == tyObject:
1116+
result.sons.add result[0].sons
1117+
result[0] = newNodeIT(nkType, result.info, result.typ)
1118+
result = transformSons(c, result)
10551119
of nkCheckedFieldExpr:
10561120
result = transformSons(c, n)
10571121
if result[0].kind != nkDotExpr:
@@ -1079,6 +1143,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
10791143
# nodes into an empty node.
10801144
if nfTransf in n.flags: return n
10811145
pushTransCon(c, newTransCon(owner))
1146+
c.genResult = c.getCurrOwner().kind in routineKinds and c.transCon.owner.ast.len > resultPos and c.transCon.owner.ast[resultPos] != nil
10821147
result = transform(c, n)
10831148
popTransCon(c)
10841149
incl(result.flags, nfTransf)

0 commit comments

Comments
 (0)