Skip to content

Commit d608f82

Browse files
committed
Default fields
1 parent ae7b53e commit d608f82

File tree

8 files changed

+245
-223
lines changed

8 files changed

+245
-223
lines changed

compiler/parser.nim

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
10021002
optInd(p, result)
10031003
result.add(parseExpr(p))
10041004
else:
1005-
result.add(newNodeP(nkEmpty, p))
1005+
result.add(p.emptyNode)
10061006

10071007
proc parseTuple(p: var TParser, indentAllowed = false): PNode =
10081008
#| inlTupleDecl = 'tuple'
@@ -1898,11 +1898,17 @@ proc parseObjectCase(p: var TParser): PNode =
18981898
#| | IND{=} objectBranches)
18991899
result = newNodeP(nkRecCase, p)
19001900
getTokNoInd(p)
1901-
var a = newNodeP(nkIdentDefs, p)
1902-
a.add(identWithPragma(p))
1903-
eat(p, tkColon)
1904-
a.add(parseTypeDesc(p))
1905-
a.add(p.emptyNode)
1901+
var a = parseIdentColonEquals(p, {withPragma})
1902+
# var a = newNodeP(nkIdentDefs, p)
1903+
# a.add(identWithPragma(p))
1904+
# eat(p, tkColon)
1905+
# a.add(parseTypeDesc(p))
1906+
# if p.tok.tokType == tkEquals:
1907+
# getTok(p)
1908+
# optInd(p, result)
1909+
# a.add(parseExpr(p))
1910+
# else:
1911+
# a.add(p.emptyNode)
19061912
result.add(a)
19071913
if p.tok.tokType == tkColon: getTok(p)
19081914
flexComment(p, result)

compiler/semobjconstr.nim

Lines changed: 127 additions & 191 deletions
Large diffs are not rendered by default.

compiler/semtypes.nim

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -711,18 +711,15 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
711711
if a != father: father.add a
712712
of nkIdentDefs:
713713
checkMinSonsLen(n, 3, c.config)
714-
var a: PNode
715-
if father.kind != nkRecList and n.len >= 4: a = newNodeI(nkRecList, n.info)
716-
else: a = newNodeI(nkEmpty, n.info)
717-
if n[^1].kind != nkEmpty:
718-
localError(c.config, n[^1].info, errInitHereNotAllowed)
719714
var typ: PType
720715
if n[^2].kind == nkEmpty:
721716
localError(c.config, n.info, errTypeExpected)
722717
typ = errorType(c)
723718
else:
724719
typ = semTypeNode(c, n[^2], nil)
725720
propagateToOwner(rectype, typ)
721+
var a: PNode = if father.kind != nkRecList and n.len > 3: newNodeI(nkRecList, n.info)
722+
else: newNodeI(nkEmpty, n.info)
726723
var fieldOwner = if c.inGenericContext > 0: c.getCurrOwner
727724
else: rectype.sym
728725
for i in 0..<n.len-2:
@@ -743,6 +740,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
743740
inc(pos)
744741
if containsOrIncl(check, f.name.id):
745742
localError(c.config, info, "attempt to redefine: '" & f.name.s & "'")
743+
var fSym = newSymNode(f)
744+
if n[^1].kind != nkEmpty:
745+
n[^1] = semConstExpr(c, n[^1])
746+
fSym.sym.ast = n[^1]
747+
elif typ.kind in {tyRange, tyOrdinal}: #Node flag? Handle embedded objects?
748+
fSym.sym.ast = semConstExpr(c, newIntNode(nkIntLit, firstOrd(c.config, typ)))
746749
if a.kind == nkEmpty: father.add newSymNode(f)
747750
else: a.add newSymNode(f)
748751
styleCheckDef(c.config, f)

compiler/transf.nim

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
# * introduces method dispatchers
1818
# * performs lambda lifting for closure support
1919
# * transforms 'defer' into a 'try finally' statement
20+
# * generates default field values for objects and transforms object contructors
2021

2122
import
2223
options, ast, astalgo, trees, msgs,
@@ -44,7 +45,7 @@ type
4445
module: PSym
4546
transCon: PTransCon # top of a TransCon stack
4647
inlining: int # > 0 if we are in inlining context (copy vars)
47-
nestedProcs: int # > 0 if we are in a nested proc
48+
genResult: bool # XXX
4849
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
4950
deferDetected, tooEarly: bool
5051
graph: ModuleGraph
@@ -383,7 +384,7 @@ proc transformYield(c: PTransf, n: PNode): PNode =
383384
let rhs = transform(c, e)
384385
result.add(asgnTo(lhs, rhs))
385386

386-
inc(c.transCon.yieldStmts)
387+
inc c.transCon.yieldStmts
387388
if c.transCon.yieldStmts <= 1:
388389
# common case
389390
result.add(c.transCon.forLoopBody)
@@ -658,7 +659,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
658659

659660
let body = transformBody(c.graph, iter, true)
660661
pushInfoContext(c.graph.config, n.info)
661-
inc(c.inlining)
662+
inc c.inlining
662663
stmtList.add(transform(c, body))
663664
#findWrongOwners(c, stmtList.pnode)
664665
dec(c.inlining)
@@ -743,13 +744,13 @@ proc transformCall(c: PTransf, n: PNode): PNode =
743744
var j = 1
744745
while j < n.len:
745746
var a = transform(c, n[j])
746-
inc(j)
747+
inc j
747748
if isConstExpr(a):
748749
while (j < n.len):
749750
let b = transform(c, n[j])
750751
if not isConstExpr(b): break
751752
a = evalOp(op.magic, n, a, b, nil, c.graph)
752-
inc(j)
753+
inc j
753754
result.add(a)
754755
if result.len == 2: result = result[1]
755756
elif magic == mAddr:
@@ -828,13 +829,13 @@ proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
828829
var j = 0
829830
while j < args.len:
830831
var a = args[j]
831-
inc(j)
832+
inc j
832833
if isConstExpr(a):
833834
while j < args.len:
834835
let b = args[j]
835836
if not isConstExpr(b): break
836837
a = evalOp(op.magic, result, a, b, nil, g)
837-
inc(j)
838+
inc j
838839
result.add(a)
839840
if result.len == 2: result = result[1]
840841
else:
@@ -882,6 +883,47 @@ proc hoistParamsUsedInDefault(c: PTransf, call, letSection, defExpr: PNode): PNo
882883
let hoisted = hoistParamsUsedInDefault(c, call, letSection, defExpr[i])
883884
if hoisted != nil: defExpr[i] = hoisted
884885

886+
import nimsets
887+
proc caseBranchMatchesExpr(branch, matched: PNode): bool =
888+
for i in 0 ..< branch.len-1:
889+
if branch[i].kind == nkRange:
890+
if overlap(branch[i], matched): return true
891+
elif exprStructuralEquivalent(branch[i], matched):
892+
return true
893+
894+
proc pickCaseBranch(caseExpr, matched: PNode): int =
895+
let endsWithElse = caseExpr[^1].kind == nkElse
896+
for i in 1..<caseExpr.len - endsWithElse.int:
897+
if caseExpr[i].caseBranchMatchesExpr(matched):
898+
return i
899+
if endsWithElse:
900+
return caseExpr.len - 1
901+
902+
proc defaultFieldsForTheUninitialized(c: PTransf, recNode: PNode): seq[PNode] =
903+
case recNode.kind
904+
of nkRecList:
905+
for field in recNode:
906+
result.add defaultFieldsForTheUninitialized(c, field)
907+
of nkRecCase:
908+
let discriminator = recNode[0]
909+
var selectedBranch: int
910+
let defaultValue = discriminator.sym.ast
911+
if defaultValue == nil:
912+
# None of the branches were explicitly selected by the user and no value
913+
# was given to the discrimator. We can assume that it will be initialized
914+
# to zero and this will select a particular branch as a result:
915+
selectedBranch = recNode.pickCaseBranch newIntNode(nkIntLit#[c.graph]#, 0)
916+
else: # Try to use default value
917+
selectedBranch = recNode.pickCaseBranch defaultValue
918+
result.add newTree(nkExprColonExpr, discriminator, defaultValue)
919+
result.add defaultFieldsForTheUninitialized(c, recNode[selectedBranch][^1])
920+
of nkSym:
921+
let field = recNode.sym
922+
if field.ast != nil: #Try to use default value
923+
result.add newTree(nkExprColonExpr, recNode, field.ast)
924+
else:
925+
assert false
926+
885927
proc transform(c: PTransf, n: PNode): PNode =
886928
when false:
887929
var oldDeferAnchor: PNode
@@ -890,6 +932,18 @@ proc transform(c: PTransf, n: PNode): PNode =
890932
nkBlockStmt, nkBlockExpr}:
891933
oldDeferAnchor = c.deferAnchor
892934
c.deferAnchor = n
935+
if c.genResult:
936+
c.genResult = false
937+
result = newNodeIT(nkStmtList, n.info, nil)
938+
let toInit = c.getCurrOwner().ast[resultPos]
939+
if toInit.typ != nil and toInit.typ.kind == tyObject:
940+
var asgnExpr = newTree(nkObjConstr, newNodeIT(nkType, toInit.info, toInit.typ))
941+
asgnExpr.typ = toInit.typ
942+
#TODO: Once the VM is ready this should be done in injectdestructors so that it can be elided properly
943+
asgnExpr.sons.add defaultFieldsForTheUninitialized(c, toInit.typ.n)
944+
result.add transform(c, newTree(nkAsgn, toInit, asgnExpr))
945+
result.add transform(c, n)
946+
return result
893947
case n.kind
894948
of nkSym:
895949
result = transformSym(c, n)
@@ -947,17 +1001,26 @@ proc transform(c: PTransf, n: PNode): PNode =
9471001
result.add(newSymNode(labl))
9481002
of nkBreakStmt: result = transformBreak(c, n)
9491003
of nkCallKinds:
950-
result = transformCall(c, n)
951-
var call = result
952-
if nfDefaultRefsParam in call.flags:
953-
# We've found a default value that references another param.
954-
# See the notes in `hoistParamsUsedInDefault` for more details.
955-
var hoistedParams = newNodeI(nkLetSection, call.info, 0)
956-
for i in 1..<call.len:
957-
let hoisted = hoistParamsUsedInDefault(c, call, hoistedParams, call[i])
958-
if hoisted != nil: call[i] = hoisted
959-
result = newTree(nkStmtListExpr, hoistedParams, call)
960-
result.typ = call.typ
1004+
# if (n[0].kind == nkSym) and (n[0].sym.magic == mReset) and (n[1].typ.kind == tyObject):
1005+
# result = newNodeIT(nkStmtList, n.info, n.typ)
1006+
# result.add transformCall(c, n)
1007+
# result.add initDefaultFields(n[1], n[1].typ.n)
1008+
# elif (n[0].kind == nkSym) and (n[0].sym.magic in {mNew, mNewFinalize}) and (n[1].typ.kind == tyRef):
1009+
# result = newNodeIT(nkStmtListExpr, n.info, n.typ)
1010+
# result.add transformCall(c, n)
1011+
# result.add initDefaultFields(n[1], n[1].typ[0].n)
1012+
# else:
1013+
result = transformCall(c, n)
1014+
var call = result
1015+
if nfDefaultRefsParam in call.flags:
1016+
# We've found a default value that references another param.
1017+
# See the notes in `hoistParamsUsedInDefault` for more details.
1018+
var hoistedParams = newNodeI(nkLetSection, call.info, 0)
1019+
for i in 1 ..< call.len:
1020+
let hoisted = hoistParamsUsedInDefault(c, call, hoistedParams, call[i])
1021+
if hoisted != nil: call[i] = hoisted
1022+
result = newTree(nkStmtListExpr, hoistedParams, call)
1023+
result.typ = call.typ
9611024
of nkAddr, nkHiddenAddr:
9621025
result = transformAddrDeref(c, n, nkDerefExpr, nkHiddenDeref)
9631026
of nkDerefExpr, nkHiddenDeref:
@@ -1013,6 +1076,13 @@ proc transform(c: PTransf, n: PNode): PNode =
10131076
return n
10141077
of nkExceptBranch:
10151078
result = transformExceptBranch(c, n)
1079+
of nkObjConstr:
1080+
result = n
1081+
if result.typ.skipTypes(abstractInst).kind == tyObject or
1082+
result.typ.skipTypes(abstractInst).kind == tyRef and result.typ.skipTypes(abstractInst)[0].kind == tyObject:
1083+
result.sons.add result[0].sons
1084+
result[0] = newNodeIT(nkType, result.info, result.typ)
1085+
result = transformSons(c, result)
10161086
else:
10171087
result = transformSons(c, n)
10181088
when false:
@@ -1034,6 +1104,7 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
10341104
# nodes into an empty node.
10351105
if nfTransf in n.flags: return n
10361106
pushTransCon(c, newTransCon(owner))
1107+
c.genResult = c.getCurrOwner().kind in routineKinds and c.transCon.owner.ast.len > resultPos and c.transCon.owner.ast[resultPos] != nil
10371108
result = transform(c, n)
10381109
popTransCon(c)
10391110
incl(result.flags, nfTransf)

compiler/vmgen.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1639,7 +1639,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
16391639
else:
16401640
if s.kind == skForVar and c.mode == emRepl: c.setSlot(s)
16411641
if s.position > 0 or (s.position == 0 and
1642-
s.kind in {skParam, skResult}):
1642+
s.kind in {skParam, skResult, skTemp}):
16431643
if dest < 0:
16441644
dest = s.position + ord(s.kind == skParam)
16451645
internalAssert(c.config, c.prc.slots[dest].kind < slotSomeTemp)

tests/constructors/tinvalid_construction.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ accept TObj()
6565
accept TObj(choice: A)
6666
reject TObj(choice: A, bc: 10) # bc is in the wrong branch
6767
accept TObj(choice: B, bc: 20)
68-
reject TObj(a: 10) # branch selected without providing discriminator
68+
accept TObj(a: 10) # branch selected with the default value "low(T)" of the discriminator
6969
reject TObj(choice: x, a: 10) # the discrimantor must be a compile-time value when a branch is selected
7070
accept TObj(choice: x) # it's OK to use run-time value when a branch is not selected
7171
accept TObj(choice: F, f: "") # match an else clause

tests/objvariant/trt_discrim.nim

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ reject:
133133
var varkind = k4
134134

135135
reject: # not immutable.
136+
case varkind
137+
of k1, k2, k3: discard KindObj(kind: varkind, i32: 1)
138+
of k4: discard KindObj(kind: varkind, f32: 2.0)
139+
else: discard KindObj(kind: varkind, str: "3")
140+
141+
reject: # complete bogus
136142
case varkind
137143
of k1, k2, k3: discard KindObj(varkind: kind, i32: 1)
138144
of k4: discard KindObj(varkind: kind, f32: 2.0)

tests/objvariant/trt_discrim_err0.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
discard """
2-
errormsg: "possible values {k1, k3, k4} are in conflict with discriminator values for selected object branch 3"
2+
errormsg: "runtime discriminator could select multiple branches, so you can't initialize these fields: str"
33
line: 17
44
"""
55

0 commit comments

Comments
 (0)