backend: refactorings so that eventually it can run on BIF directly w… (#25959)

…ithout PNode constructions; also added bif2nif.nim inspection tool
This commit is contained in:
Andreas Rumpf
2026-08-04 15:18:34 +02:00
committed by GitHub
parent 7a1e162b0c
commit 0206aa334c
6 changed files with 294 additions and 287 deletions

View File

@@ -946,6 +946,16 @@ template `[]=`*(n: PNode, i: BackwardsIndex; x: PNode) = n[n.len - i.int] = x
iterator items*(n: PNode): PNode =
for i in 0..<n.safeLen: yield n[i]
iterator sons*(n: PNode): PNode =
## Iterates over the children of `n`. Preferred over `for i in 0..<n.len: n[i]`
## as it does not rely on random indexed access (see doc/ic_backend_nif_native.md).
for i in 0..<n.safeLen: yield n[i]
iterator isons*(n: PNode): tuple[i: int, n: PNode] =
## Like `sons` but also yields the child index. Replaces
## `for i in 0..<n.len: ... n[i] ...` when `i` itself is still needed.
for i in 0..<n.safeLen: yield (i, n[i])
when defined(useNodeIds):
const nodeIdToDebug* = -1 # 2322968
var gNodeId: int

View File

@@ -40,7 +40,7 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
return false
of nkDotExpr, nkBracketExpr, nkObjUpConv, nkObjDownConv,
nkCheckedFieldExpr:
n = n[0]
n = n.firstSon
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
n = n[1]
else:
@@ -54,7 +54,7 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
if isPartOf(le, r, {pfStructural}) != arNo: return true
# we use the weaker 'canRaise' here in order to prevent too many
# annoying warnings, see #14514
if canRaise(ri[0]) and
if canRaise(ri.firstSon) and
locationEscapes(p, le, p.nestedTryStmts.len > 0):
message(p.config, le.info, warnObservableStores, $le)
# bug #19613 prevent dangerous aliasing too:
@@ -64,7 +64,7 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
if isPartOf(dest, r, {pfStructural}) != arNo: return true
proc hasNoInit(call: PNode): bool {.inline.} =
result = call[0].kind == nkSym and sfNoInit in call[0].sym.flags
result = call.firstSon.kind == nkSym and sfNoInit in call.firstSon.sym.flags
proc isHarmlessStore(p: BProc; canRaise: bool; d: TLoc): bool =
if d.k in {locTemp, locNone} or not canRaise:
@@ -97,10 +97,10 @@ proc cleanupTemp(p: BProc; returnType: PType, tmp: TLoc): bool =
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
result: var Builder, call: var CallBuilder) =
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri.firstSon)
genLineDir(p, ri)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
var typ = skipTypes(ri.firstSon.typ, abstractInst)
if typ.returnType != nil:
var flags: TAssignmentFlags = {}
if typ.returnType.kind in {tyOpenArray, tyVarargs}:
@@ -184,7 +184,7 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
while true:
case x.kind
of {nkAddr, nkHiddenAddr, nkHiddenDeref}:
x = x[0]
x = x.firstSon
of nkHiddenStdConv:
x = x[1]
else:
@@ -368,7 +368,7 @@ proc expressionsNeedsTmp(p: BProc, a: TLoc): TLoc =
genAssignment(p, result, a, {})
proc genArgStringToCString(p: BProc, n: PNode; result: var Builder; needsTmp: bool) {.inline.} =
var a = initLocExpr(p, n[0])
var a = initLocExpr(p, n.firstSon)
let tmp = withTmpIfNeeded(p, a, needsTmp)
let ra = if p.config.usesSso(): byRefLoc(p, tmp) else: tmp.rdLoc
result.addCall(cgsymValue(p.module, "nimToCStringConv"), ra)
@@ -378,9 +378,9 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
if n.kind == nkStringToCString:
genArgStringToCString(p, n, result, needsTmp)
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
var n = if n.kind != nkHiddenAddr: n else: n[0]
var n = if n.kind != nkHiddenAddr: n else: n.firstSon
openArrayLoc(p, param.typ, n, result)
elif ccgIntroducedPtr(p.config, param, call[0].typ.returnType) and
elif ccgIntroducedPtr(p.config, param, call.firstSon.typ.returnType) and
(optByRef notin param.options or not p.module.compileToCpp):
a = initLocExpr(p, n)
if n.kind in {nkCharLit..nkNilLit}:
@@ -392,7 +392,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
# bug #23748: we need to introduce a temporary here. The expression type
# will be a reference in C++ and we cannot create a temporary reference
# variable. Thus, we create a temporary pointer variable instead.
let needsIndirect = mapType(p.config, n[0].typ, mapTypeChooser(n[0]) == skParam) != ctArray
let needsIndirect = mapType(p.config, n.firstSon.typ, mapTypeChooser(n.firstSon) == skParam) != ctArray
if needsIndirect:
n.typ = n.typ.exactReplica(p.module.idgen)
n.typ.incl tfVarIsPtr
@@ -401,7 +401,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Builder; n
if needsIndirect: a.flags.incl lfIndirect
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
# means '*T'. See posix.nim for lots of examples that do that in the wild.
let callee = call[0]
let callee = call.firstSon
if callee.kind == nkSym and
{sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {} and
@@ -439,7 +439,7 @@ proc skipTrivialIndirections(n: PNode): PNode =
while true:
case result.kind
of nkDerefExpr, nkHiddenDeref, nkAddr, nkHiddenAddr, nkObjDownConv, nkObjUpConv:
result = result[0]
result = result.firstSon
of nkHiddenStdConv, nkHiddenSubConv:
result = result[1]
else: break
@@ -498,14 +498,14 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
# this is a hotspot in the compiler
var op = initLocExpr(p, ri[0])
var op = initLocExpr(p, ri.firstSon)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
var typ = skipTypes(ri.firstSon.typ, abstractInstOwned)
assert(typ.kind == tyProc)
var callee = rdLoc(op)
if p.hcrOn and ri[0].kind == nkSym:
callee.addActualSuffixForHCR(p.module.module, ri[0].sym)
if p.hcrOn and ri.firstSon.kind == nkSym:
callee.addActualSuffixForHCR(p.module.module, ri.firstSon.sym)
var res = newBuilder("")
var call = initCallBuilder(res, callee)
@@ -537,10 +537,10 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
else:
cCall(p, params, e)
var op = initLocExpr(p, ri[0])
var op = initLocExpr(p, ri.firstSon)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
var typ = skipTypes(ri.firstSon.typ, abstractInstOwned)
assert(typ.kind == tyProc)
var params = newBuilder("")
@@ -557,7 +557,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
p.s(cpsStmts).add(callProc(rp, pars, rawProc))
let rawProc = getClosureType(p.module, typ, clHalf)
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri.firstSon)
if typ.returnType != nil:
if isInvalidReturnType(p.config, typ):
# beware of 'result = p(result)'. We may need to allocate a temporary:
@@ -619,7 +619,7 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder;
discard
elif paramType.typ.kind in {tyVar} and ri[i].kind == nkHiddenAddr:
result.addArgument(argBuilder):
genArgNoParam(p, ri[i][0], result)
genArgNoParam(p, ri[i].firstSon, result)
else:
result.addArgument(argBuilder):
genArgNoParam(p, ri[i], result) #, typ.n[i].sym)
@@ -672,16 +672,16 @@ proc skipAddrDeref(node: PNode): PNode =
var isAddr = false
case n.kind
of nkAddr, nkHiddenAddr:
n = n[0]
n = n.firstSon
isAddr = true
of nkDerefExpr, nkHiddenDeref:
n = n[0]
n = n.firstSon
else: return n
if n.kind == nkObjDownConv: n = n[0]
if n.kind == nkObjDownConv: n = n.firstSon
if isAddr and n.kind in {nkDerefExpr, nkHiddenDeref}:
result = n[0]
result = n.firstSon
elif n.kind in {nkAddr, nkHiddenAddr}:
result = n[0]
result = n.firstSon
else:
result = node
@@ -694,29 +694,29 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Builder) =
# if the parameter is lying (tyVar) and thus we required an additional deref,
# skip the deref:
var ri = ri[i]
while ri.kind == nkObjDownConv: ri = ri[0]
while ri.kind == nkObjDownConv: ri = ri.firstSon
let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink})
if t.kind in {tyVar}:
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
let x = if ri.kind == nkHiddenAddr: ri.firstSon else: ri
if x.typ.kind == tyPtr:
genArgNoParam(p, x, result)
result.add("->")
elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
genArgNoParam(p, x[0], result)
elif x.kind in {nkHiddenDeref, nkDerefExpr} and x.firstSon.typ.kind == tyPtr:
genArgNoParam(p, x.firstSon, result)
result.add("->")
else:
genArgNoParam(p, x, result)
result.add(".")
elif t.kind == tyPtr:
if ri.kind in {nkAddr, nkHiddenAddr}:
genArgNoParam(p, ri[0], result)
genArgNoParam(p, ri.firstSon, result)
result.add(".")
else:
genArgNoParam(p, ri, result)
result.add("->")
else:
ri = skipAddrDeref(ri)
if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri[0]
if ri.kind in {nkAddr, nkHiddenAddr}: ri = ri.firstSon
genArgNoParam(p, ri, result) #, typ.n[i].sym)
result.add(".")
@@ -734,8 +734,8 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
if i+1 < pat.len and pat[i+1] in {'+', '@'}:
let ri = ri[j]
if ri.kind in nkCallKinds:
let typ = skipTypes(ri[0].typ, abstractInst)
if pat[i+1] == '+': genArgNoParam(p, ri[0], result)
let typ = skipTypes(ri.firstSon.typ, abstractInst)
if pat[i+1] == '+': genArgNoParam(p, ri.firstSon, result)
result.add("(")
if 1 < ri.len:
var callBuilder: CallBuilder = default(CallBuilder)
@@ -752,7 +752,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
inc i
elif i+1 < pat.len and pat[i+1] == '[':
var arg = ri[j].skipAddrDeref
while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg[0]
while arg.kind in {nkAddr, nkHiddenAddr, nkObjDownConv}: arg = arg.firstSon
genArgNoParam(p, arg, result)
#result.add debugTree(arg, 0, 10)
else:
@@ -775,18 +775,18 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Bu
result.add(substr(pat, start, i - 1))
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op = initLocExpr(p, ri[0])
var op = initLocExpr(p, ri.firstSon)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
var typ = skipTypes(ri.firstSon.typ, abstractInst)
assert(typ.kind == tyProc)
# don't call '$' here for efficiency:
let pat = $ri[0].sym.loc.snippet
let pat = $ri.firstSon.sym.loc.snippet
internalAssert p.config, pat.len > 0
if pat.contains({'#', '(', '@', '\''}):
var pl = newBuilder("")
genPatternCall(p, ri, pat, typ, pl)
# simpler version of 'fixupCall' that works with the pl+params combination:
var typ = skipTypes(ri[0].typ, abstractInst)
var typ = skipTypes(ri.firstSon.typ, abstractInst)
if typ.returnType != nil:
if p.module.compileToCpp and lfSingleUse in d.flags:
# do not generate spurious temporaries for C++! For C we're better off
@@ -817,14 +817,14 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# generates a crappy ObjC call
var op = initLocExpr(p, ri[0])
var op = initLocExpr(p, ri.firstSon)
var pl = newBuilder("[")
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
var typ = skipTypes(ri.firstSon.typ, abstractInst)
assert(typ.kind == tyProc)
# don't call '$' here for efficiency:
let pat = $ri[0].sym.loc.snippet
let pat = $ri.firstSon.sym.loc.snippet
internalAssert p.config, pat.len > 0
var start = 3
if ' ' in pat:
@@ -903,27 +903,27 @@ proc isInactiveDestructorCall(p: BProc, e: PNode): bool =
We want to return early but the 'finally' section is traversed before
the 'let args = ...' statement. We exploit this to generate better
code for 'return'. ]#
result = e.len == 2 and e[0].kind == nkSym and
e[0].sym.name.s == "=destroy" and notYetAlive(e[1].skipAddr)
result = e.len == 2 and e.firstSon.kind == nkSym and
e.firstSon.sym.name.s == "=destroy" and notYetAlive(e[1].skipAddr)
proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, ri):
return
when defined(icDbgHash):
if ri[0].typ == nil:
echo "NILCALLEE kind=", ri[0].kind,
" sym=", (if ri[0].kind == nkSym: ri[0].sym.name.s else: "-"),
" symKind=", (if ri[0].kind == nkSym: $ri[0].sym.kind else: "-"),
" flags=", (if ri[0].kind == nkSym: $ri[0].sym.flags else: "-"),
" lazy=", nfLazyType in ri[0].flags,
if ri.firstSon.typ == nil:
echo "NILCALLEE kind=", ri.firstSon.kind,
" sym=", (if ri.firstSon.kind == nkSym: ri.firstSon.sym.name.s else: "-"),
" symKind=", (if ri.firstSon.kind == nkSym: $ri.firstSon.sym.kind else: "-"),
" flags=", (if ri.firstSon.kind == nkSym: $ri.firstSon.sym.flags else: "-"),
" lazy=", nfLazyType in ri.firstSon.flags,
" inProc=", (if p.prc != nil: p.prc.name.s else: "NIL"),
" module=", p.module.module.name.s
raiseAssert "nil callee type, see NILCALLEE above"
if ri[0].typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
if ri.firstSon.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyOwned}).callConv == ccClosure:
genClosureCall(p, le, ri, d)
elif ri[0].kind == nkSym and sfInfixCall in ri[0].sym.flags:
elif ri.firstSon.kind == nkSym and sfInfixCall in ri.firstSon.sym.flags:
genInfixCall(p, le, ri, d)
elif ri[0].kind == nkSym and sfNamedParamCall in ri[0].sym.flags:
elif ri.firstSon.kind == nkSym and sfNamedParamCall in ri.firstSon.sym.flags:
genNamedParamCall(p, ri, d)
else:
genPrefixCall(p, le, ri, d)

View File

@@ -137,7 +137,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
else: result = OnUnknown
else: result = OnUnknown
of nkDerefExpr, nkHiddenDeref:
case n[0].typ.kind
case n.firstSon.typ.kind
of tyVar, tyLent: result = OnUnknown
of tyPtr: result = OnStack
of tyRef: result = OnHeap
@@ -145,7 +145,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
result = OnUnknown
doAssert(false, "getStorageLoc")
of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
result = getStorageLoc(n[0])
result = getStorageLoc(n.firstSon)
else: result = OnUnknown
proc canMove(p: BProc, n: PNode; dest: TLoc): bool =
@@ -904,27 +904,27 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
let mt = mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam)
let mt = mapType(p.config, e.firstSon.typ, mapTypeChooser(e.firstSon) == skParam)
if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then?
expr(p, e[0], d)
if e[0].typ.skipTypes(abstractInstOwned).kind == tyRef:
expr(p, e.firstSon, d)
if e.firstSon.typ.skipTypes(abstractInstOwned).kind == tyRef:
d.storage = OnHeap
else:
var a: TLoc
var typ = e[0].typ
var typ = e.firstSon.typ
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass:
typ = typ.last
typ = typ.skipTypes(abstractInstOwned)
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and
p.module.compileToCpp and e[0].kind == nkHiddenAddr and
p.module.compileToCpp and e.firstSon.kind == nkHiddenAddr and
# don't override existing location:
d.k == locNone:
d = initLocExprSingleUse(p, e[0][0])
d = initLocExprSingleUse(p, e.firstSon.firstSon)
return
else:
a = initLocExprSingleUse(p, e[0])
a = initLocExprSingleUse(p, e.firstSon)
# bug #23453 #25265
if e.typ != nil and e.typ.skipTypes(abstractInst).kind == tyObject:
@@ -964,14 +964,14 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
proc cowBracket(p: BProc; n: PNode) =
if n.kind == nkBracketExpr and optSeqDestructors in p.config.globalOptions and
not p.config.usesSso():
let strCandidate = n[0]
let strCandidate = n.firstSon
if strCandidate.typ.skipTypes(abstractInst).kind == tyString:
var a: TLoc = initLocExpr(p, strCandidate)
let raa = byRefLoc(p, a)
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimPrepareStrMutationV2"), raa)
proc cow(p: BProc; n: PNode) {.inline.} =
if n.kind == nkHiddenAddr: cowBracket(p, n[0])
if n.kind == nkHiddenAddr: cowBracket(p, n.firstSon)
template ignoreConv(e: PNode): bool =
let destType = e.typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink})
@@ -980,22 +980,22 @@ template ignoreConv(e: PNode): bool =
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand:
if e[0].typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}:
var a: TLoc = initLocExpr(p, e[0])
if e.firstSon.typ.skipTypes(abstractInstOwned).kind in {tyRef, tyPtr}:
var a: TLoc = initLocExpr(p, e.firstSon)
putIntoDest(p, d, e, cAddr(a.snippet), a.storage)
#Message(e.info, warnUser, "HERE NEW &")
elif mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam) == ctArray or isCppRef(p, e.typ):
expr(p, e[0], d)
elif mapType(p.config, e.firstSon.typ, mapTypeChooser(e.firstSon) == skParam) == ctArray or isCppRef(p, e.typ):
expr(p, e.firstSon, d)
# bug #19497
d.lode = e
else:
let ssoStrSub = p.config.usesSso() and e[0].kind == nkBracketExpr and
e[0][0].typ.skipTypes(abstractVar).kind == tyString
var a: TLoc = initLocExpr(p, e[0], if ssoStrSub: {lfEnforceDeref, lfPrepareForMutation} else: {})
if e[0].kind in {nkHiddenStdConv, nkHiddenSubConv, nkConv} and not ignoreConv(e[0]):
let ssoStrSub = p.config.usesSso() and e.firstSon.kind == nkBracketExpr and
e.firstSon.firstSon.typ.skipTypes(abstractVar).kind == tyString
var a: TLoc = initLocExpr(p, e.firstSon, if ssoStrSub: {lfEnforceDeref, lfPrepareForMutation} else: {})
if e.firstSon.kind in {nkHiddenStdConv, nkHiddenSubConv, nkConv} and not ignoreConv(e.firstSon):
# addr (conv x) introduces a temp because `conv x` is not a rvalue
# transform addr ( conv ( x ) ) -> conv ( addr ( x ) )
var exprLoc: TLoc = initLocExpr(p, e[0][1])
var exprLoc: TLoc = initLocExpr(p, e.firstSon[1])
var tmp = getTemp(p, e.typ, needsInit=false)
putIntoDest(p, tmp, e, cCast(getTypeDesc(p.module, e.typ), addrLoc(p.config, exprLoc)))
putIntoDest(p, d, e, rdLoc(tmp))
@@ -1006,7 +1006,7 @@ template inheritLocation(d: var TLoc, a: TLoc) =
if d.k == locNone: d.storage = a.storage
proc genRecordFieldAux(p: BProc, e: PNode, d: var TLoc, a: var TLoc) =
a = initLocExpr(p, e[0])
a = initLocExpr(p, e.firstSon)
if e[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux")
d.inheritLocation(a)
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
@@ -1014,7 +1014,7 @@ proc genRecordFieldAux(p: BProc, e: PNode, d: var TLoc, a: var TLoc) =
proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
var
i: int = 0
var a: TLoc = initLocExpr(p, e[0])
var a: TLoc = initLocExpr(p, e.firstSon)
let tupType = a.t.skipTypes(abstractInst+{tyVar}+tyUserTypeClasses) # ref #25227
assert tupType.kind == tyTuple
d.inheritLocation(a)
@@ -1076,8 +1076,8 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym, ty: PType) =
for i in 1..<e.len:
var it = e[i]
assert(it.kind in nkCallKinds)
assert(it[0].kind == nkSym)
let op = it[0].sym
assert(it.firstSon.kind == nkSym)
let op = it.firstSon.sym
if op.magic == mNot: it = it[1]
let disc = it[2].skipConv
assert(disc.kind == nkSym)
@@ -1154,23 +1154,23 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym, ty: PType) =
raiseInstr(p, p.s(cpsStmts))
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
assert e[0].kind == nkDotExpr
assert e.firstSon.kind == nkDotExpr
if optFieldCheck in p.options:
var a: TLoc = default(TLoc)
genRecordFieldAux(p, e[0], d, a)
genRecordFieldAux(p, e.firstSon, d, a)
let ty = skipTypes(a.t, abstractInst + tyUserTypeClasses)
var r = rdLoc(a)
let f = e[0][1].sym
let f = e.firstSon[1].sym
let field = lookupFieldAgain(p, ty, f, r)
if field.loc.snippet == "": fillObjectFields(p.module, ty)
if field.loc.snippet == "":
internalError(p.config, e.info, "genCheckedRecordField") # generate the checks:
genFieldCheck(p, e, r, field, ty)
r = dotField(r, field.loc.snippet)
putIntoDest(p, d, e[0], r, a.storage)
putIntoDest(p, d, e.firstSon, r, a.storage)
r.freeze
else:
genRecordField(p, e[0], d)
genRecordField(p, e.firstSon, d)
proc genUncheckedArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a = initLocExpr(p, x)
@@ -1345,14 +1345,14 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
putIntoDest(p, d, n, subscript(dataField(p, ra), rcb), a.storage)
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
var ty = skipTypes(n[0].typ, abstractVarRange + tyUserTypeClasses)
var ty = skipTypes(n.firstSon.typ, abstractVarRange + tyUserTypeClasses)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.elementType, abstractVarRange)
case ty.kind
of tyUncheckedArray: genUncheckedArrayElem(p, n, n[0], n[1], d)
of tyArray: genArrayElem(p, n, n[0], n[1], d)
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, n[0], n[1], d)
of tySequence, tyString: genSeqElem(p, n, n[0], n[1], d)
of tyCstring: genCStringElem(p, n, n[0], n[1], d)
of tyUncheckedArray: genUncheckedArrayElem(p, n, n.firstSon, n[1], d)
of tyArray: genArrayElem(p, n, n.firstSon, n[1], d)
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, n.firstSon, n[1], d)
of tySequence, tyString: genSeqElem(p, n, n.firstSon, n[1], d)
of tyCstring: genCStringElem(p, n, n.firstSon, n[1], d)
of tyTuple: genTupleElem(p, n, d)
else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
discard getTypeDesc(p.module, n.typ)
@@ -1940,7 +1940,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
var check: PNode = nil
if e[i].len == 3 and optFieldCheck in p.options:
check = e[i][2]
genFieldObjConstr(p, ty, useTemp, isRef, e[i][0], e[i][1], check, d, r, e.info)
genFieldObjConstr(p, ty, useTemp, isRef, e[i].firstSon, e[i][1], check, d, r, e.info)
if useTemp:
if d.k == locNone:
@@ -1980,13 +1980,13 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
else:
# generate call to newSeq before adding the elements per hand:
genNewSeqAux(p, dest[], lit, n.len == 0)
for i in 0..<n.len:
arr = initLoc(locExpr, n[i], OnHeap)
for i, ni in isons(n):
arr = initLoc(locExpr, ni, OnHeap)
let lit = cIntLiteral(i)
let rd = rdLoc dest[]
arr.snippet = subscript(dataField(p, rd), lit)
arr.storage = OnHeap # we know that sequences are on the heap
expr(p, n[i], arr)
expr(p, ni, arr)
gcUsage(p.config, n)
if doesAlias:
if d.k == locNone:
@@ -2176,7 +2176,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
let ra = rdLoc(a)
let la = cIntValue(lengthOrd(p.config, a.t))
putIntoDest(p, b, e, ra & cArgumentSeparator & la, a.storage)
else: internalError(p.config, e[0].info, "genRepr()")
else: internalError(p.config, e.firstSon.info, "genRepr()")
let rb = rdLoc(b)
let rti = genTypeInfoV1(p.module, elemType(t), e.info)
putIntoDest(p, d, e, cgCall("reprOpenArray", rb, rti), a.storage)
@@ -2218,7 +2218,7 @@ proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
proc genGetTypeInfoV2(p: BProc, e: PNode, d: var TLoc) =
let t = e[1].typ
if isFinal(t) or e[0].sym.name.s != "getDynamicTypeInfo":
if isFinal(t) or e.firstSon.sym.name.s != "getDynamicTypeInfo":
# ordinary static type information
putIntoDest(p, d, e, genTypeInfoV2(p.module, t, e.info))
else:
@@ -2249,12 +2249,12 @@ template genDollarIt(p: BProc, n: PNode, d: var TLoc, frmt: untyped) =
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var a = e[1]
if a.kind == nkHiddenAddr: a = a[0]
if a.kind == nkHiddenAddr: a = a.firstSon
var typ = skipTypes(a.typ, abstractVar + tyUserTypeClasses)
case typ.kind
of tyOpenArray, tyVarargs:
# Bug #9279, len(toOpenArray()) has to work:
if a.kind in nkCallKinds and a[0].kind == nkSym and a[0].sym.magic == mSlice:
if a.kind in nkCallKinds and a.firstSon.kind == nkSym and a.firstSon.sym.magic == mSlice:
# magic: pass slice to openArray:
var m = initLocExpr(p, a[1])
var b = initLocExpr(p, a[2])
@@ -2318,7 +2318,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc, noinit = false) =
return
assert(d.k == locNone)
var x = e[1]
if x.kind in {nkAddr, nkHiddenAddr}: x = x[0]
if x.kind in {nkAddr, nkHiddenAddr}: x = x.firstSon
var a = initLocExpr(p, x)
var b = initLocExpr(p, e[2])
let t = skipTypes(e[1].typ, {tyVar})
@@ -2440,7 +2440,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
# so, we skip the unnecessary range check: This is a semantical extension
# that code now relies on. :-/ XXX
let ea = if e[2].kind in {nkChckRange, nkChckRange64}:
e[2][0]
e[2].firstSon
else:
e[2]
a = initLocExpr(p, ea)
@@ -2451,7 +2451,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
let it = e[1][i]
var currentExpr: Snippet
if it.kind == nkRange:
x = initLocExpr(p, it[0])
x = initLocExpr(p, it.firstSon)
y = initLocExpr(p, it[1])
let rca = rdCharLoc(a)
let rcx = rdCharLoc(x)
@@ -2689,13 +2689,13 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
genSomeCast(p, e, d)
proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc = initLocExpr(p, n.firstSon)
var dest = skipTypes(n.typ, abstractVar)
if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and
checkUnsignedConversions notin p.config.legacyFeatures):
discard "no need to generate a check because it was disabled"
else:
let n0t = n[0].typ
let n0t = n.firstSon.typ
# emit range check:
if n0t.kind in {tyUInt, tyUInt64}:
@@ -2735,7 +2735,7 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc) =
p.s(cpsStmts).addCallStmt(raiser, rca, firstVal, lastVal)
raiseInstr(p, p.s(cpsStmts))
if sameBackendTypeIgnoreRange(dest, n[0].typ):
if sameBackendTypeIgnoreRange(dest, n.firstSon.typ):
# don't cast so an address can be taken for `var` conversions
let val = rdCharLoc(a)
putIntoDest(p, d, n, wrapPar(val), a.storage)
@@ -2751,14 +2751,14 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) =
genSomeCast(p, e, d)
proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc = initLocExpr(p, n.firstSon)
let arg = if p.config.usesSso(): byRefLoc(p, a) else: rdLoc(a)
putIntoDest(p, d, n,
cgCall(p, "nimToCStringConv", arg),
a.storage)
proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc = initLocExpr(p, n.firstSon)
if p.module.compileToCpp:
# fixes for const qualifier; bug #12703; bug #19588
putIntoDest(p, d, n,
@@ -2941,7 +2941,7 @@ proc genEnumToStr(p: BProc, e: PNode, d: var TLoc) =
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
case op
of mAsgn:
let kind = if e[0].sym.name.s == "=sink": nkSinkAsgn else: nkAsgn
let kind = if e.firstSon.sym.name.s == "=sink": nkSinkAsgn else: nkAsgn
let lhs = e[1].skipHiddenAddr
let n = newTreeI(kind, e.info, lhs, e[2])
n.typ = e.typ
@@ -3056,11 +3056,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
if e[1].kind == nkDotExpr:
dotExpr = e[1]
elif e[1].kind == nkCheckedFieldExpr:
dotExpr = e[1][0]
dotExpr = e[1].firstSon
else:
dotExpr = nil
internalError(p.config, e.info, "unknown ast")
let t = dotExpr[0].typ.skipTypes({tyTypeDesc})
let t = dotExpr.firstSon.typ.skipTypes({tyTypeDesc})
let tname = getTypeDesc(p.module, t, dkVar)
let member =
if t.kind == tyTuple:
@@ -3090,7 +3090,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
mInSet, mXorSet:
genSetOp(p, e, d, op)
of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat:
var opr = e[0].sym
var opr = e.firstSon.sym
# Why would anyone want to set nodecl to one of these hardcoded magics?
# - not sure, and it wouldn't work if the symbol behind the magic isn't
# somehow forward-declared from some other usage, but it is *possible*
@@ -3125,7 +3125,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mEcho: genEcho(p, e[1].skipConv)
of mArrToSeq: genArrToSeq(p, e, d)
of mNLen..mNError, mSlurp..mQuoteAst:
localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e[0].sym.name.s))
localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e.firstSon.sym.name.s))
of mSpawn:
when defined(leanCompiler):
p.config.quitOrRaise "compiler built without support for the 'spawn' statement"
@@ -3193,7 +3193,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
for it in e.sons:
if it.kind == nkRange:
idx = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter
a = initLocExpr(p, it[0])
a = initLocExpr(p, it.firstSon)
b = initLocExpr(p, it[1])
var aa: Snippet = ""
rdSetElemLoc(p.config, a, e.typ, aa)
@@ -3222,7 +3222,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
for it in e.sons:
if it.kind == nkRange:
idx = getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt)) # our counter
a = initLocExpr(p, it[0])
a = initLocExpr(p, it.firstSon)
b = initLocExpr(p, it[1])
var aa: Snippet = ""
rdSetElemLoc(p.config, a, e.typ, aa)
@@ -3258,8 +3258,8 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
elif d.k == locNone:
d = getTemp(p, n.typ)
for i in 0..<n.len:
var it = n[i]
for i, ni in isons(n):
var it = ni
if it.kind == nkExprColonExpr: it = it[1]
# Do not produce code for void types
if it.typ != nil and isEmptyType(it.typ): continue
@@ -3275,7 +3275,7 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
genAssignment(p, d, tmp, {})
proc isConstClosure(n: PNode): bool {.inline.} =
result = n[0].kind == nkSym and isRoutine(n[0].sym) and
result = n.firstSon.kind == nkSym and isRoutine(n.firstSon.sym) and
n[1].kind == nkNilLit
proc genClosure(p: BProc, n: PNode, d: var TLoc) =
@@ -3292,9 +3292,9 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
putIntoDest(p, d, n, tmp, OnStatic)
else:
var tmp: TLoc
var a = initLocExpr(p, n[0])
var a = initLocExpr(p, n.firstSon)
var b = initLocExpr(p, n[1])
if n[0].skipConv.kind == nkClosure:
if n.firstSon.skipConv.kind == nkClosure:
internalError(p.config, n.info, "closure to closure created")
# tasyncawait.nim breaks with this optimization:
when false:
@@ -3313,11 +3313,11 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
var arr: TLoc
if not handleConstExpr(p, n, d):
if d.k == locNone: d = getTemp(p, n.typ)
for i in 0..<n.len:
for i, ni in isons(n):
arr = initLoc(locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), d.storage)
let lit = cIntLiteral(i)
arr.snippet = subscript(rdLoc(d), lit)
expr(p, n[i], arr)
expr(p, ni, arr)
proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) =
requestConstImpl(p, sym)
@@ -3336,7 +3336,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} =
if hasNimFrame and frameName == "":
inc p.labels
frameName = "FR" & rope(p.labels) & "_"
let theMacro = it[0].sym
let theMacro = it.firstSon.sym
add p.s(cpsStmts), initFrameNoDebug(p, frameName,
makeCString theMacro.name.s,
quotedFilename(p.config, theMacro.info), it.info.line.int)
@@ -3357,7 +3357,7 @@ proc genStmtList(p: BProc, n: PNode) =
from parampatterns import isLValue
proc upConv(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc = initLocExpr(p, n.firstSon)
let dest = skipTypes(n.typ, abstractPtrs)
if optObjCheck in p.options and not isObjLackingTypeField(dest):
var nilCheck = ""
@@ -3381,9 +3381,9 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
# skip cast when types map to the same C type
# this avoids invalid C code like `*(T*)&x` for types that can't have their address taken (e.g., WASM __externref_t)
if getTypeDesc(p.module, n.typ) == getTypeDesc(p.module, n[0].typ):
expr(p, n[0], d)
elif n[0].typ.kind != tyObject:
if getTypeDesc(p.module, n.typ) == getTypeDesc(p.module, n.firstSon.typ):
expr(p, n.firstSon, d)
elif n.firstSon.typ.kind != tyObject:
let destTyp = getTypeDesc(p.module, n.typ)
let val = rdLoc(a)
if n.isLValue:
@@ -3407,8 +3407,8 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
a.storage)
proc downConv(p: BProc, n: PNode, d: var TLoc) =
var arg = n[0]
while arg.kind == nkObjDownConv: arg = arg[0]
var arg = n.firstSon
while arg.kind == nkObjDownConv: arg = arg.firstSon
let dest = skipTypes(n.typ, abstractPtrs)
let src = skipTypes(arg.typ, abstractPtrs)
@@ -3566,8 +3566,8 @@ proc genConstStmt(p: BProc, n: PNode) =
assert delayedCodegen(p.module)
let m = p.module
for it in n:
if it[0].kind == nkSym:
let sym = it[0].sym
if it.firstSon.kind == nkSym:
let sym = it.firstSon.sym
if not isSimpleConst(sym.typ) and sym.itemId.item in m.alive and genConstSetup(p, sym):
genConstDefinition(m, p, sym)
@@ -3698,7 +3698,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
nkCallStrLit:
genLineDir(p, n) # may be redundant, it is generated in fixupCall as well
let op = n[0]
let op = n.firstSon
if n.typ.isNil:
# discard the value:
var a: TLoc = default(TLoc)
@@ -3747,7 +3747,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkIfExpr, nkIfStmt: genIf(p, n, d)
of nkWhen:
# This should be a "when nimvm" node.
expr(p, n[1][0], d)
expr(p, n[1].firstSon, d)
of nkObjDownConv: downConv(p, n, d)
of nkObjUpConv: upConv(p, n, d)
of nkChckRangeF, nkChckRange64, nkChckRange: genRangeChck(p, n, d)
@@ -3770,7 +3770,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else: # enforce addressable consts for exportc
let m = p.module
for it in n:
let symNode = skipPragmaExpr(it[0])
let symNode = skipPragmaExpr(it.firstSon)
if symNode.kind == nkSym and sfExportc in symNode.sym.flags:
requestConstImpl(p, symNode.sym)
# else: consts generated lazily on use
@@ -3789,7 +3789,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
# See tests/run/tcnstseq3 for an example that would fail otherwise.
genAsgn(p, n, fastAsgn=p.prc != nil)
of nkDiscardStmt:
let ex = n[0]
let ex = n.firstSon
if ex.kind != nkEmpty:
genLineDir(p, n)
var a: TLoc = initLocExprSingleUse(p, ex)
@@ -3815,7 +3815,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkPragma: genPragma(p, n)
of nkPragmaBlock:
var inUncheckedAssignSection = 0
let pragmaList = n[0]
let pragmaList = n.firstSon
for pi in pragmaList:
if whichPragma(pi) == wCast:
case whichPragma(pi[1])
@@ -3877,7 +3877,7 @@ proc containsOpaqueImportcFieldAux(t: PType; n: PNode): bool =
if containsOpaqueImportcFieldAux(t, child):
return true
of nkRecCase:
if containsOpaqueImportcFieldAux(t, n[0]):
if containsOpaqueImportcFieldAux(t, n.firstSon):
return true
for i in 1..<n.len:
let branch = n[i]
@@ -4017,16 +4017,16 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
# generate only 1 field for default value of union
return
of nkRecCase:
getNullValueAux(p, t, obj[0], constOrNil, result, init, isConst, info)
getNullValueAux(p, t, obj.firstSon, constOrNil, result, init, isConst, info)
var branch = Zero
if constOrNil != nil:
## find kind value, default is zero if not specified
for i in 1..<constOrNil.len:
if constOrNil[i].kind == nkExprColonExpr:
if constOrNil[i][0].sym.name.id == obj[0].sym.name.id:
if constOrNil[i].firstSon.sym.name.id == obj.firstSon.sym.name.id:
branch = getOrdValue(constOrNil[i][1])
break
elif i == obj[0].sym.position:
elif i == obj.firstSon.sym.position:
branch = getOrdValue(constOrNil[i])
break
@@ -4036,7 +4036,7 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
# branches are allowed to have no members (b.len == 0), in this case they don't need initializer
var fieldName: string = ""
if b.kind == nkRecList and not isEmptyCaseObjectBranch(b):
fieldName = "_" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch
fieldName = "_" & mangleRecFieldName(p.module, obj.firstSon.sym) & "_" & $selectedBranch
result.addField(init, name = ""): # anonymous union
var branchInit: StructInitializer
result.addStructInitializer(branchInit, kind = siNamedStruct):
@@ -4070,8 +4070,8 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
if constOrNil != nil:
for i in 1..<constOrNil.len:
if constOrNil[i].kind == nkExprColonExpr:
assert constOrNil[i][0].kind == nkSym, "illformed object constr; the field is not a sym"
if constOrNil[i][0].sym.name.id == field.name.id:
assert constOrNil[i].firstSon.kind == nkSym, "illformed object constr; the field is not a sym"
if constOrNil[i].firstSon.sym.name.id == field.name.id:
genBracedInit(p, constOrNil[i][1], isConst, field.typ, result)
break fieldInit
elif i == field.position:
@@ -4121,11 +4121,10 @@ proc genConstSimpleList(p: BProc, n: PNode; isConst: bool; result: var Builder)
if p.vccAndC and n.len == 0 and n.typ.kind == tyArray:
result.addField(arrInit, name = ""):
getDefaultValue(p, n.typ.elementType, n.info, result)
for i in 0..<n.len:
let it = n[i]
for it in n.sons:
var ind, val: PNode
if it.kind == nkExprColonExpr:
ind = it[0]
ind = it.firstSon
val = it[1]
else:
ind = it
@@ -4139,8 +4138,8 @@ proc genConstTuple(p: BProc, n: PNode; isConst: bool; tup: PType; result: var Bu
if p.vccAndC and n.len == 0:
result.addField(tupleInit, name = "dummy"):
result.addIntValue(0)
for i in 0..<n.len:
var it = n[i]
for i, ni in isons(n):
var it = ni
if it.kind == nkExprColonExpr:
it = it[1]
# Do not produce code for void types
@@ -4174,9 +4173,9 @@ proc genConstSeq(p: BProc, n: PNode, t: PType; isConst: bool; result: var Builde
def.addField(structInit, name = "data"):
var arrInit: StructInitializer
def.addStructInitializer(arrInit, kind = siArray):
for i in 0..<n.len:
for ni in n.sons:
def.addField(arrInit, name = ""):
genBracedInit(p, n[i], isConst, base, def)
genBracedInit(p, ni, isConst, base, def)
p.module.s[cfsStrData].add extract(def)
result.add cCast(typ = getTypeDesc(p.module, t), value = cAddr(tmpName))
@@ -4202,9 +4201,9 @@ proc genConstSeqV2(p: BProc, n: PNode, t: PType; isConst: bool; result: var Buil
def.addField(structInit, name = "data"):
var arrInit: StructInitializer
def.addStructInitializer(arrInit, kind = siArray):
for i in 0..<n.len:
for ni in n.sons:
def.addField(arrInit, name = ""):
genBracedInit(p, n[i], isConst, base, def)
genBracedInit(p, ni, isConst, base, def)
p.module.s[cfsStrData].add extract(def)
var resultInit: StructInitializer
@@ -4252,10 +4251,10 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; resul
var closureInit: StructInitializer
result.addStructInitializer(closureInit, kind = siOrderedStruct):
result.addField(closureInit, name = "ClP_0"):
if n[0].kind == nkNilLit:
if n.firstSon.kind == nkNilLit:
result.add(NimNil)
else:
var d: TLoc = initLocExpr(p, n[0])
var d: TLoc = initLocExpr(p, n.firstSon)
result.add(cCast(typ = getClosureType(p.module, typ, clHalfWithEnv), value = rdLoc(d)))
result.addField(closureInit, name = "ClE_0"):
result.add(NimNil)

View File

@@ -34,10 +34,10 @@ proc registerTraverseProc(p: BProc, v: PSym) =
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
if n.kind == nkEmpty:
result = false
elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
if n[0].kind == nkSym and sfConstructor in n[0].sym.flags:
elif n.kind in nkCallKinds and n.firstSon != nil and n.firstSon.typ != nil and n.firstSon.typ.skipTypes(abstractInst).kind == tyProc:
if n.firstSon.kind == nkSym and sfConstructor in n.firstSon.sym.flags:
result = true
elif isInvalidReturnType(conf, n[0].typ, true):
elif isInvalidReturnType(conf, n.firstSon.typ, true):
# var v = f()
# is transformed into: var v; f(addr v)
# where 'f' **does not** initialize the result!
@@ -104,7 +104,7 @@ proc genVarTuple(p: BProc, n: PNode) =
return
# check only the first son
var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
var forHcr = treatGlobalDifferentlyForHCR(p.module, n.firstSon.sym)
let hcrCond = if forHcr: getTempName(p.module) else: ""
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] = @[]
# determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
@@ -166,7 +166,7 @@ proc genVarTuple(p: BProc, n: PNode) =
p.s(cpsLocals).addInPlaceOp(BitOr, NimBool,
hcrCond,
cCall("hcrRegisterGlobal",
getModuleDllPath(p.module, n[0].sym),
getModuleDllPath(p.module, n.firstSon.sym),
'"' & curr.loc.snippet & '"',
cSizeof(rc),
curr.tp,
@@ -174,8 +174,8 @@ proc genVarTuple(p: BProc, n: PNode) =
proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
if ri.kind in nkCallKinds and (ri[0].kind != nkSym or
ri[0].sym.magic == mNone):
if ri.kind in nkCallKinds and (ri.firstSon.kind != nkSym or
ri.firstSon.sym.magic == mNone):
genAsgnCall(p, le, ri, a)
else:
# this is a hacky way to fix #1181 (tmissingderef)::
@@ -219,9 +219,9 @@ template preserveBreakIdx(body: untyped): untyped =
proc genState(p: BProc, n: PNode) =
internalAssert p.config, n.len == 1
let n0 = n[0]
let n0 = n.firstSon
if n0.kind == nkIntLit:
let idx = n[0].intVal
let idx = n.firstSon.intVal
p.s(cpsStmts).addLabel("STATE" & $idx)
elif n0.kind == nkStrLit:
p.s(cpsStmts).addLabel(n0.strVal)
@@ -248,7 +248,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int, isReturnStmt
# and generate a copy of its sons
var finallyStmt = tryStmt.fin
if finallyStmt != nil:
genStmts(p, finallyStmt[0])
genStmts(p, finallyStmt.firstSon)
dec p.withinBlockLeaveActions
@@ -268,7 +268,7 @@ proc genGotoState(p: BProc, n: PNode) =
# switch (x.state) {
# case 0: goto STATE0;
# ...
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc = initLocExpr(p, n.firstSon)
let ra = rdLoc(a)
p.s(cpsStmts).addSwitchStmt(ra):
p.flags.incl beforeRetNeeded
@@ -277,7 +277,7 @@ proc genGotoState(p: BProc, n: PNode) =
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlockLen)
p.s(cpsStmts).addGoto("BeforeRet_")
var statesCounter = lastOrd(p.config, n[0].typ)
var statesCounter = lastOrd(p.config, n.firstSon.typ)
if n.len >= 2 and n[1].kind == nkIntLit:
statesCounter = getInt(n[1])
let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
@@ -290,8 +290,8 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
d = initLoc(locExpr, n, OnUnknown)
if n[0].kind == nkClosure:
a = initLocExpr(p, n[0][1])
if n.firstSon.kind == nkClosure:
a = initLocExpr(p, n.firstSon[1])
let ra = a.rdLoc
d.snippet = cOp(LessThan,
subscript(
@@ -299,7 +299,7 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
cIntValue(1)),
cIntValue(0))
else:
a = initLocExpr(p, n[0])
a = initLocExpr(p, n.firstSon)
let ra = a.rdLoc
# the environment is guaranteed to contain the 'state' field at offset 1:
d.snippet = cOp(LessThan,
@@ -327,18 +327,18 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Builder) =
proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): Snippet =
var res = newBuilder("")
var argBuilder = default(CallBuilder) # not init, only building params
let typ = skipTypes(call[0].typ, abstractInst)
let typ = skipTypes(call.firstSon.typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1..<call.len:
#if it's a type we can just generate here another initializer as we are in an initializer context
if call[i].kind == nkCall and call[i][0].kind == nkSym and call[i][0].sym.kind == skType:
if call[i].kind == nkCall and call[i].firstSon.kind == nkSym and call[i].firstSon.sym.kind == skType:
res.addArgument(argBuilder):
res.add genCppInitializer(p.module, p, call[i][0].sym.typ, didGenTemp)
res.add genCppInitializer(p.module, p, call[i].firstSon.sym.typ, didGenTemp)
else:
#We need to test for temp in globals, see: #23657
let param =
if typ[i].kind in {tyVar} and call[i].kind == nkHiddenAddr:
call[i][0]
call[i].firstSon
else:
call[i]
if not param.typ.isCompileTimeOnly and (param.kind != nkBracketExpr or param.typ.kind in
@@ -356,8 +356,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
return
let imm = isAssignedImmediately(p.config, value)
let isCppCtorCall = p.module.compileToCpp and imm and
value.kind in nkCallKinds and value[0].kind == nkSym and
v.typ.kind != tyPtr and sfConstructor in value[0].sym.flags
value.kind in nkCallKinds and value.firstSon.kind == nkSym and
v.typ.kind != tyPtr and sfConstructor in value.firstSon.sym.flags
var targetProc = p
var valueBuilder = newBuilder("")
potentialValueInit(p, v, value, valueBuilder)
@@ -470,7 +470,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
finishIfStmt(p.s(cpsStmts), hcrInit)
proc genSingleVar(p: BProc, a: PNode) =
let v = a[0].sym
let v = a.firstSon.sym
if sfCompileTime in v.flags:
# fix issue #12640
# {.global, compileTime.} pragma in proc
@@ -478,15 +478,15 @@ proc genSingleVar(p: BProc, a: PNode) =
discard
else:
return
genSingleVar(p, v, a[0], a[2])
genSingleVar(p, v, a.firstSon, a[2])
proc genClosureVar(p: BProc, a: PNode) =
var immediateAsgn = a[2].kind != nkEmpty
var v: TLoc = initLocExpr(p, a[0])
var v: TLoc = initLocExpr(p, a.firstSon)
genLineDir(p, a)
if immediateAsgn:
loadInto(p, a[0], a[2], v)
elif sfNoInit notin a[0][1].sym.flags:
loadInto(p, a.firstSon, a[2], v)
elif sfNoInit notin a.firstSon[1].sym.flags:
constructLoc(p, v)
proc genVarStmt(p: BProc, n: PNode) =
@@ -495,7 +495,7 @@ proc genVarStmt(p: BProc, n: PNode) =
of nkCommentStmt: discard
of nkIdentDefs:
# can be a lifted var nowadays ...
if it[0].kind == nkSym:
if it.firstSon.kind == nkSym:
genSingleVar(p, it)
else:
genClosureVar(p, it)
@@ -529,7 +529,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
if it.len == 2:
var scope: ScopeBuilder
startSimpleBlock(p, scope)
a = initLocExprSingleUse(p, it[0])
a = initLocExprSingleUse(p, it.firstSon)
lelse = getLabel(p)
inc(p.labels)
let ra = rdLoc(a)
@@ -548,7 +548,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
elif it.len == 1:
var scope: ScopeBuilder
startSimpleBlock(p, scope)
expr(p, it[0], d)
expr(p, it.firstSon, d)
endSimpleBlock(p, scope)
else: internalError(p.config, n.info, "genIf()")
if n.len > 1: fixLabel(p, lend)
@@ -557,7 +557,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
if nfPreventCg in t.flags: return
p.flags.incl beforeRetNeeded
genLineDir(p, t)
if (t[0].kind != nkEmpty): genStmts(p, t[0])
if (t.firstSon.kind != nkEmpty): genStmts(p, t.firstSon)
blockLeaveActions(p,
howManyTrys = p.nestedTryStmts.len,
howManyExcepts = p.inExceptBlockLen,
@@ -605,22 +605,21 @@ proc genComputedGoto(p: BProc; n: PNode) =
let n = n.flattenStmts()
var casePos = -1
var arraySize: int = 0
for i in 0..<n.len:
let it = n[i]
for i, it in isons(n):
if it.kind == nkCaseStmt:
if lastSon(it).kind != nkOfBranch:
localError(p.config, it.info,
"case statement must be exhaustive for computed goto"); return
casePos = i
if enumHasHoles(it[0].typ):
if enumHasHoles(it.firstSon.typ):
localError(p.config, it.info,
"case statement cannot work on enums with holes for computed goto"); return
let aSize = lengthOrd(p.config, it[0].typ)
let aSize = lengthOrd(p.config, it.firstSon.typ)
if aSize > 10_000:
localError(p.config, it.info,
"case statement has too many cases for computed goto"); return
arraySize = toInt(aSize)
if firstOrd(p.config, it[0].typ) != 0:
if firstOrd(p.config, it.firstSon.typ) != 0:
localError(p.config, it.info,
"case statement has to start at 0 for computed goto"); return
if casePos < 0:
@@ -642,7 +641,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
genStmts(p, n[j])
let caseStmt = n[casePos]
var a: TLoc = initLocExpr(p, caseStmt[0])
var a: TLoc = initLocExpr(p, caseStmt.firstSon)
let ra = a.rdLoc
# first goto:
p.s(cpsStmts).addComputedGoto(subscript(tmp, ra))
@@ -681,7 +680,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
else:
genStmts(p, it)
var a: TLoc = initLocExpr(p, caseStmt[0])
var a: TLoc = initLocExpr(p, caseStmt.firstSon)
let ra = a.rdLoc
p.s(cpsStmts).addComputedGoto(subscript(tmp, ra))
endSimpleBlock(p, scope)
@@ -704,7 +703,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
if loopBody.stmtsContainPragma(wComputedGoto) and
hasComputedGoto in CC[p.config.cCompiler].props:
# for closure support weird loop bodies are generated:
if loopBody.len == 2 and loopBody[0].kind == nkEmpty:
if loopBody.len == 2 and loopBody.firstSon.kind == nkEmpty:
loopBody = loopBody[1]
genComputedGoto(p, loopBody)
else:
@@ -712,8 +711,8 @@ proc genWhileStmt(p: BProc, t: PNode) =
p.breakIdx = startBlockWith(p):
stmt = initWhileStmt(p.s(cpsStmts), cIntValue(1))
p.blocks[p.breakIdx].isLoop = true
a = initLocExpr(p, t[0])
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
a = initLocExpr(p, t.firstSon)
if (t.firstSon.kind != nkIntLit) or (t.firstSon.intVal == 0):
let ra = a.rdLoc
var label: TLabel = ""
assignLabel(p.blocks[p.breakIdx], label)
@@ -739,10 +738,10 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
preserveBreakIdx:
var scope: ScopeBuilder
p.breakIdx = startSimpleBlock(p, scope)
if n[0].kind != nkEmpty:
if n.firstSon.kind != nkEmpty:
# named block?
assert(n[0].kind == nkSym)
var sym = n[0].sym
assert(n.firstSon.kind == nkSym)
var sym = n.firstSon.sym
backendEnsureMutable sym
sym.locImpl.k = locOther
sym.positionImpl = p.breakIdx+1
@@ -756,8 +755,8 @@ proc genParForStmt(p: BProc, t: PNode) =
genLineDir(p, t)
preserveBreakIdx:
let forLoopVar = t[0].sym
assignLocalVar(p, t[0])
let forLoopVar = t.firstSon.sym
assignLocalVar(p, t.firstSon)
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t[1]
@@ -768,7 +767,7 @@ proc genParForStmt(p: BProc, t: PNode) =
var stepNode: PNode = nil
# $n at the beginning because of #9710
if call.len == 4: # procName(a, b, annotation)
if call[0].sym.name.s == "||": # `||`(a, b, annotation)
if call.firstSon.sym.name.s == "||": # `||`(a, b, annotation)
p.s(cpsStmts).addCPragma("omp " & call[3].getStr)
else:
p.s(cpsStmts).addCPragma(call[3].getStr)
@@ -791,10 +790,10 @@ proc genParForStmt(p: BProc, t: PNode) =
proc genBreakStmt(p: BProc, t: PNode) =
var idx = p.breakIdx
if t[0].kind != nkEmpty:
if t.firstSon.kind != nkEmpty:
# named break?
assert(t[0].kind == nkSym)
var sym = t[0].sym
assert(t.firstSon.kind == nkSym)
var sym = t.firstSon.sym
doAssert(sym.loc.k == locOther)
idx = sym.position-1
else:
@@ -854,7 +853,7 @@ proc finallyActions(p: BProc) =
if p.nestedTryStmts[i].inExcept:
let finallyBlock = p.nestedTryStmts[i].fin
if finallyBlock != nil:
genSimpleBlock(p, finallyBlock[0])
genSimpleBlock(p, finallyBlock.firstSon)
return
proc raiseInstr(p: BProc; result: var Builder) =
@@ -871,12 +870,12 @@ proc raiseInstr(p: BProc; result: var Builder) =
# + ord(p.nestedTryStmts[L-1].inExcept)])
proc genRaiseStmt(p: BProc, t: PNode) =
if t[0].kind != nkEmpty:
var a: TLoc = initLocExprSingleUse(p, t[0])
if t.firstSon.kind != nkEmpty:
var a: TLoc = initLocExprSingleUse(p, t.firstSon)
finallyActions(p)
var e = rdLoc(a)
discard getTypeDesc(p.module, t[0].typ)
var typ = skipTypes(t[0].typ, abstractPtrs)
discard getTypeDesc(p.module, t.firstSon.typ)
var typ = skipTypes(t.firstSon.typ, abstractPtrs)
case p.config.exc
of excCpp:
blockLeaveActions(p, howManyTrys = 0, howManyExcepts = p.inExceptBlockLen)
@@ -913,7 +912,7 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
for i in 0..<b.len - 1:
let rlabel {.inject.} = labl
if b[i].kind == nkRange:
x = initLocExpr(p, b[i][0])
x = initLocExpr(p, b[i].firstSon)
y = initLocExpr(p, b[i][1])
let ra {.inject.} = rdCharLoc(e)
let rb {.inject.} = rdCharLoc(x)
@@ -936,7 +935,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
exprBlock(p, t[i][^1], d)
p.s(cpsStmts).addGoto(lend)
else:
exprBlock(p, t[i][0], d)
exprBlock(p, t[i].firstSon, d)
result = lend
template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
@@ -964,7 +963,7 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: untyped) =
var a: TLoc = initLocExpr(p, t[0])
var a: TLoc = initLocExpr(p, t.firstSon)
var lend = genIfForCaseUntil(p, t, d, t.len-1, a, rangeFormat, eqFormat)
fixLabel(p, lend)
@@ -999,7 +998,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
var bitMask = math.nextPowerOfTwo(strings) - 1
var branches: seq[Builder]
newSeq(branches, bitMask + 1)
var a: TLoc = initLocExpr(p, t[0]) # first pass: generate ifs+goto:
var a: TLoc = initLocExpr(p, t.firstSon) # first pass: generate ifs+goto:
var labId = p.labels
for i in 1..<t.len:
inc(p.labels)
@@ -1044,7 +1043,7 @@ proc branchHasTooBigRange(b: PNode): bool =
for it in b:
# last son is block
if (it.kind == nkRange) and
it[1].intVal - it[0].intVal > RangeExpandLimit:
it[1].intVal - it.firstSon.intVal > RangeExpandLimit:
return true
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
@@ -1064,11 +1063,11 @@ proc genCaseRange(p: BProc, branch: PNode, info: var SwitchCaseBuilder) =
if hasSwitchRange in CC[p.config.cCompiler].props:
var litA = newBuilder("")
var litB = newBuilder("")
genLiteral(p, branch[j][0], litA)
genLiteral(p, branch[j].firstSon, litA)
genLiteral(p, branch[j][1], litB)
p.s(cpsStmts).addCaseRange(info, extract(litA), extract(litB))
else:
var v = copyNode(branch[j][0])
var v = copyNode(branch[j].firstSon)
while v.intVal <= branch[j][1].intVal:
var litA = newBuilder("")
genLiteral(p, v, litA)
@@ -1084,7 +1083,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
var splitPoint = ifSwitchSplitPoint(p, n)
# generate if part (might be empty):
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc = initLocExpr(p, n.firstSon)
var lend: TLabel = ""
if splitPoint > 0:
lend = genIfForCaseUntil(p, n, d, splitPoint, a):
@@ -1130,7 +1129,7 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
case skipTypes(t[0].typ, abstractVarRange).kind
case skipTypes(t.firstSon.typ, abstractVarRange).kind
of tyString:
genStringCase(p, t, tyString, d)
of tyCstring:
@@ -1146,7 +1145,7 @@ proc genCase(p: BProc, t: PNode, d: var TLoc) =
removeSinglePar(cOp(Equal, ra, rb))):
p.s(cpsStmts).addGoto(rlabel)
else:
if t[0].kind == nkSym and sfGoto in t[0].sym.flags:
if t.firstSon.kind == nkSym and sfGoto in t.firstSon.sym.flags:
genGotoForCase(p, t)
else:
genOrdinalCase(p, t, d)
@@ -1203,12 +1202,12 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if t.kind == nkHiddenTryStmt:
lineCg(p, cpsStmts, "try {$n", [])
expr(p, t[0], d)
expr(p, t.firstSon, d)
lineCg(p, cpsStmts, "}$n", [])
else:
startBlockWith(p):
p.s(cpsStmts).add("try {\n")
expr(p, t[0], d)
expr(p, t.firstSon, d)
endBlockWith(p):
p.s(cpsStmts).add("}\n")
@@ -1238,7 +1237,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
scope = initScope(p.s(cpsStmts))
# we handled the error:
linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp])
expr(p, t[i][0], d)
expr(p, t[i].firstSon, d)
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
endBlockWith(p):
if hasIf:
@@ -1311,7 +1310,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
# general except section:
startBlockWith(p):
p.s(cpsStmts).add("catch (...) {\n")
genExceptBranchBody(t[i][0])
genExceptBranchBody(t[i].firstSon)
endBlockWith(p):
p.s(cpsStmts).add("}\n")
catchAllPresent = true
@@ -1351,7 +1350,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
var scope: ScopeBuilder
startSimpleBlock(p, scope)
genStmts(p, t[^1][0])
genStmts(p, t[^1].firstSon)
linefmt(p, cpsStmts, "if (T$1_) std::rethrow_exception(T$1_);$n", [etmp])
endSimpleBlock(p, scope)
@@ -1389,7 +1388,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
p.nestedTryStmts.add((fin, false, t.kind == nkHiddenTryStmt, 0.Natural))
startBlockWith(p):
p.s(cpsStmts).add("try {\n")
expr(p, t[0], d)
expr(p, t.firstSon, d)
endBlockWith(p):
p.s(cpsStmts).add("}\n")
@@ -1407,7 +1406,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
catchAllPresent = true
startBlockWith(p):
p.s(cpsStmts).add("catch (...) {\n")
genExceptBranchBody(t[i][0])
genExceptBranchBody(t[i].firstSon)
endBlockWith(p):
p.s(cpsStmts).add("}\n")
else:
@@ -1434,17 +1433,17 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
# finally requires catch all presence
startBlockWith(p):
p.s(cpsStmts).add("catch (...) {\n")
genStmts(p, t[^1][0])
genStmts(p, t[^1].firstSon)
line(p, cpsStmts, "throw;\n")
endBlockWith(p):
p.s(cpsStmts).add("}\n")
genSimpleBlock(p, t[^1][0])
genSimpleBlock(p, t[^1].firstSon)
proc bodyCanRaise(p: BProc; n: PNode): bool =
case n.kind
of nkCallKinds:
result = canRaiseDisp(p, n[0])
result = canRaiseDisp(p, n.firstSon)
if not result:
# also check the arguments:
for i in 1 ..< n.len:
@@ -1472,7 +1471,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
expr(p, t[0], d)
expr(p, t.firstSon, d)
var ifStmt = default(IfBuilder)
var scope = default(ScopeBuilder)
@@ -1511,7 +1510,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
innerScope = initScope(p.s(cpsStmts))
# we handled the exception, remember this:
p.s(cpsStmts).addAssignment(cDeref("nimErr_"), NimFalse)
expr(p, t[i][0], d)
expr(p, t[i].firstSon, d)
else:
if not innerIsIf:
innerIsIf = true
@@ -1570,16 +1569,16 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
if i < t.len and t[i].kind == nkFinally:
var finallyScope: ScopeBuilder
startSimpleBlock(p, finallyScope)
if not bodyCanRaise(p, t[i][0]):
if not bodyCanRaise(p, t[i].firstSon):
# this is an important optimization; most destroy blocks are detected not to raise an
# exception and so we help the C optimizer by not mutating nimErr_ pointlessly:
genStmts(p, t[i][0])
genStmts(p, t[i].firstSon)
else:
# pretend we did handle the error for the safe execution of the 'finally' section:
p.procSec(cpsLocals).addVar(kind = Local, name = "oldNimErrFin" & $lab & "_", typ = NimBool)
p.s(cpsStmts).addAssignment("oldNimErrFin" & $lab & "_", cDeref("nimErr_"))
p.s(cpsStmts).addAssignment(cDeref("nimErr_"), NimFalse)
genStmts(p, t[i][0])
genStmts(p, t[i].firstSon)
# this is correct for all these cases:
# 1. finally is run during ordinary control flow
# 2. finally is run after 'except' block handling: these however set the
@@ -1672,7 +1671,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
cOp(Equal, dotField(safePoint, "status"), cIntValue(0))))
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
p.nestedTryStmts.add((fin, quirkyExceptions, t.kind == nkHiddenTryStmt, 0.Natural))
expr(p, t[0], d)
expr(p, t.firstSon, d)
var quirkyIf = default(IfBuilder)
var quirkyScope = default(ScopeBuilder)
var isScope = false
@@ -1709,7 +1708,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
scope = initScope(p.s(cpsStmts))
if not quirkyExceptions:
p.s(cpsStmts).addFieldAssignment(safePoint, "status", cIntValue(0))
expr(p, t[i][0], d)
expr(p, t[i].firstSon, d)
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
endBlockWith(p):
if exceptIfInited:
@@ -1772,7 +1771,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
p.finallySafePoints.add(safePoint)
var finallyScope: ScopeBuilder
startSimpleBlock(p, finallyScope)
genStmts(p, t[i][0])
genStmts(p, t[i].firstSon)
# pretend we handled the exception in a 'finally' so that we don't
# re-raise the unhandled one but instead keep the old one (it was
# not popped either):
@@ -1844,7 +1843,7 @@ proc genAsmStmt(p: BProc, t: PNode) =
var s = newRopeAppender()
var asmSyntax = ""
if (let p = t[0]; p.kind == nkPragma):
if (let p = t.firstSon; p.kind == nkPragma):
for i in p:
if whichPragma(i) == wAsmSyntax:
asmSyntax = i[1].strVal
@@ -1870,8 +1869,8 @@ proc genAsmStmt(p: BProc, t: PNode) =
proc determineSection(n: PNode): TCFileSection =
result = cfsProcHeaders
if n.len >= 1 and n[0].kind in {nkStrLit..nkTripleStrLit}:
let sec = n[0].strVal
if n.len >= 1 and n.firstSon.kind in {nkStrLit..nkTripleStrLit}:
let sec = n.firstSon.strVal
if sec.startsWith("/*TYPESECTION*/"): result = cfsForwardTypes # TODO WORKAROUND
elif sec.startsWith("/*VARSECTION*/"): result = cfsVars
elif sec.startsWith("/*INCLUDESECTION*/"): result = cfsHeaders
@@ -1889,8 +1888,7 @@ proc genEmit(p: BProc, t: PNode) =
line(p, cpsStmts, s)
proc genPragma(p: BProc, n: PNode) =
for i in 0..<n.len:
let it = n[i]
for i, it in isons(n):
case whichPragma(it)
of wEmit: genEmit(p, it)
of wPush:
@@ -1937,35 +1935,35 @@ when false:
expr(p, call, d)
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var dotExpr = e[0]
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0]
var a = initLocExpr(p, e[0])
var dotExpr = e.firstSon
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr.firstSon
var a = initLocExpr(p, e.firstSon)
var tmp: TLoc = getTemp(p, a.t)
expr(p, e[1], tmp)
if p.inUncheckedAssignSection == 0:
let field = dotExpr[1].sym
genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field)
genDiscriminantCheck(p, a, tmp, dotExpr.firstSon.typ, field)
message(p.config, e.info, warnCaseTransition)
genAssignment(p, a, tmp, {})
proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
if e[0].kind == nkSym and sfGoto in e[0].sym.flags:
if e.firstSon.kind == nkSym and sfGoto in e.firstSon.sym.flags:
genLineDir(p, e)
genGotoVar(p, e[1])
elif optFieldCheck in p.options and isDiscriminantField(e[0]):
elif optFieldCheck in p.options and isDiscriminantField(e.firstSon):
genLineDir(p, e)
asgnFieldDiscriminant(p, e)
elif p.config.usesSso() and e[0].kind == nkBracketExpr and
e[0][0].typ.skipTypes(abstractVar).kind == tyString:
elif p.config.usesSso() and e.firstSon.kind == nkBracketExpr and
e.firstSon.firstSon.typ.skipTypes(abstractVar).kind == tyString:
# nimsso: s[i] = c → nimStrPutV3(&s, i, c) (handles COW internally)
genLineDir(p, e)
var base = initLocExpr(p, e[0][0])
var idx = initLocExpr(p, e[0][1])
var base = initLocExpr(p, e.firstSon.firstSon)
var idx = initLocExpr(p, e.firstSon[1])
var rhs = initLocExpr(p, e[1])
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimStrPutV3"),
byRefLoc(p, base), rdLoc(idx), rdCharLoc(rhs))
else:
let le = e[0]
let le = e.firstSon
let ri = e[1]
var a: TLoc = initLoc(locNone, le, OnUnknown)
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)

View File

@@ -767,11 +767,11 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
check: var IntSet; result: var Builder; unionPrefix = "") =
case n.kind
of nkRecList:
for i in 0..<n.len:
genRecordFieldsAux(m, n[i], rectype, check, result, unionPrefix)
for ni in n.sons:
genRecordFieldsAux(m, ni, rectype, check, result, unionPrefix)
of nkRecCase:
if n[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
genRecordFieldsAux(m, n[0], rectype, check, result, unionPrefix)
if n.firstSon.kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
genRecordFieldsAux(m, n.firstSon, rectype, check, result, unionPrefix)
# prefix mangled name with "_U" to avoid clashes with other field names,
# since identifiers are not allowed to start with '_'
var unionBody = newBuilder("")
@@ -780,7 +780,7 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
of nkOfBranch, nkElse:
let k = lastSon(n[i])
if k.kind != nkSym:
let structName = "_" & mangleRecFieldName(m, n[0].sym) & "_" & $i
let structName = "_" & mangleRecFieldName(m, n.firstSon.sym) & "_" & $i
var a = newBuilder("")
genRecordFieldsAux(m, k, rectype, check, a, unionPrefix & $structName & ".")
if a.buf.len != 0:
@@ -1075,9 +1075,9 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
let owner = hashOwner(t.sym)
if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
var vals: seq[(string, int)] = @[]
for i in 0..<t.n.len:
assert(t.n[i].kind == nkSym)
let field = t.n[i].sym
for son in t.n.sons:
assert(son.kind == nkSym)
let field = son.sym
vals.add((field.name.s, field.position.int))
gDebugInfo.registerEnum(EnumDesc(size: size, owner: owner, id: t.sym.id,
name: t.sym.name.s, values: vals))
@@ -1497,14 +1497,14 @@ proc genObjectFields(m: BModule; typ, origType: PType, n: PNode, expr: Rope;
case n.kind
of nkRecList:
if n.len == 1:
genObjectFields(m, typ, origType, n[0], expr, info)
genObjectFields(m, typ, origType, n.firstSon, expr, info)
elif n.len > 0:
var tmp = getTempName(m) & "_" & $n.len
genTNimNodeArray(m, tmp, n.len)
for i in 0..<n.len:
for i, ni in isons(n):
var tmp2 = getNimNode(m)
m.s[cfsTypeInit3].addSubscriptAssignment(tmp, cIntValue(i), cAddr(tmp2))
genObjectFields(m, typ, origType, n[i], tmp2, info)
genObjectFields(m, typ, origType, ni, tmp2, info)
m.s[cfsTypeInit3].addFieldAssignment(expr, "len", n.len)
m.s[cfsTypeInit3].addFieldAssignment(expr, "kind", 2)
m.s[cfsTypeInit3].addFieldAssignment(expr, "sons",
@@ -1513,8 +1513,8 @@ proc genObjectFields(m: BModule; typ, origType: PType, n: PNode, expr: Rope;
m.s[cfsTypeInit3].addFieldAssignment(expr, "len", n.len)
m.s[cfsTypeInit3].addFieldAssignment(expr, "kind", 2)
of nkRecCase:
assert(n[0].kind == nkSym)
var field = n[0].sym
assert(n.firstSon.kind == nkSym)
var field = n.firstSon.sym
var tmp = discriminatorTableName(m, typ, field)
var L = lengthOrd(m.config, field.typ)
assert L > 0
@@ -1558,7 +1558,7 @@ proc genObjectFields(m: BModule; typ, origType: PType, n: PNode, expr: Rope;
internalError(m.config, b.info, "genObjectFields; nkOfBranch broken")
for j in 0..<b.len - 1:
if b[j].kind == nkRange:
var x = toInt(getOrdValue(b[j][0]))
var x = toInt(getOrdValue(b[j].firstSon))
var y = toInt(getOrdValue(b[j][1]))
while x <= y:
m.s[cfsTypeInit3].addSubscriptAssignment(tmp, cIntValue(x), cAddr(tmp2))
@@ -1649,9 +1649,9 @@ proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
var firstNimNode = m.typeNodes
var hasHoles = false
enumNames.addStructInitializer(enumNamesInit, kind = siArray):
for i in 0..<typ.n.len:
assert(typ.n[i].kind == nkSym)
var field = typ.n[i].sym
for i, son in isons(typ.n):
assert(son.kind == nkSym)
var field = son.sym
var elemNode = getNimNode(m)
enumNames.addField(enumNamesInit, name = ""):
if field.ast == nil:
@@ -2268,7 +2268,7 @@ proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rop
proc retrieveSym(n: PNode): PSym =
case n.kind
of nkPostfix: result = retrieveSym(n[1])
of nkPragmaExpr, nkTypeDef: result = retrieveSym(n[0])
of nkPragmaExpr, nkTypeDef: result = retrieveSym(n.firstSon)
of nkSym: result = n.sym
else: result = nil

View File

@@ -955,12 +955,12 @@ proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
proc initLocExprSingleUse(p: BProc, e: PNode): TLoc =
result = initLoc(locNone, e, OnUnknown)
if e.kind in nkCallKinds and (e[0].kind != nkSym or e[0].sym.magic == mNone):
if e.kind in nkCallKinds and (e.firstSon.kind != nkSym or e.firstSon.sym.magic == mNone):
# We cannot check for tfNoSideEffect here because of mutable parameters.
discard "bug #8202; enforce evaluation order for nested calls for C++ too"
# We may need to consider that 'f(g())' cannot be rewritten to 'tmp = g(); f(tmp)'
# if 'tmp' lacks a move/assignment operator.
if e[0].kind == nkSym and sfCompileToCpp in e[0].sym.flags:
if e.firstSon.kind == nkSym and sfCompileToCpp in e.firstSon.sym.flags:
result.flags.incl lfSingleUse
else:
result.flags.incl lfSingleUse
@@ -1104,7 +1104,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2)
if isCall:
let n = lib.path
var a: TLoc = initLocExpr(m.initProc, n[0])
var a: TLoc = initLocExpr(m.initProc, n.firstSon)
let callee = rdLoc(a)
var params: seq[Snippet] = @[]
for i in 1..<n.len-1:
@@ -1260,15 +1260,15 @@ proc containsResult(n: PNode): bool =
of succ(nkEmpty)..pred(nkSym), succ(nkSym)..nkNilLit, harmless:
discard
of nkReturnStmt:
for i in 0..<n.len:
if containsResult(n[i]): return true
result = n.len > 0 and n[0].kind == nkEmpty
for ni in n.sons:
if containsResult(ni): return true
result = n.len > 0 and n.firstSon.kind == nkEmpty
of nkSym:
if n.sym.kind == skResult:
result = true
else:
for i in 0..<n.len:
if containsResult(n[i]): return true
for ni in n.sons:
if containsResult(ni): return true
proc easyResultAsgn(n: PNode): PNode =
result = nil
@@ -1278,12 +1278,12 @@ proc easyResultAsgn(n: PNode): PNode =
while i < n.len and n[i].kind in harmless: inc i
if i < n.len: result = easyResultAsgn(n[i])
of nkAsgn, nkFastAsgn, nkSinkAsgn:
if n[0].kind == nkSym and n[0].sym.kind == skResult and not containsResult(n[1]):
if n.firstSon.kind == nkSym and n.firstSon.sym.kind == skResult and not containsResult(n[1]):
incl n.flags, nfPreventCg
return n[1]
of nkReturnStmt:
if n.len > 0:
result = easyResultAsgn(n[0])
result = easyResultAsgn(n.firstSon)
if result != nil: incl n.flags, nfPreventCg
else: discard
@@ -1320,7 +1320,7 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
result = allPathsAsgnResult(p, it)
if result != Unknown: return result
of nkAsgn, nkFastAsgn, nkSinkAsgn:
if n[0].kind == nkSym and n[0].sym.kind == skResult:
if n.firstSon.kind == nkSym and n.firstSon.sym.kind == skResult:
if not containsResult(n[1]):
if allPathsAsgnResult(p, n[1]) == InitRequired:
result = InitRequired
@@ -1333,19 +1333,19 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
result = allPathsAsgnResult(p, n[1])
of nkReturnStmt:
if n.len > 0:
if n[0].kind == nkEmpty and result != InitSkippable:
if n.firstSon.kind == nkEmpty and result != InitSkippable:
# This is a bare `return` statement, if `result` was not initialized
# anywhere else (or if we're not sure about this) let's require it to be
# initialized. This avoids cases like #9286 where this heuristic lead to
# wrong code being generated.
result = InitRequired
else: result = allPathsAsgnResult(p, n[0])
else: result = allPathsAsgnResult(p, n.firstSon)
of nkIfStmt, nkIfExpr:
var exhaustive = false
result = InitSkippable
for it in n:
# Every condition must not use 'result':
if it.len == 2 and containsResult(it[0]):
if it.len == 2 and containsResult(it.firstSon):
return InitRequired
if it.len == 1: exhaustive = true
allPathsInBranch(it.lastSon)
@@ -1353,9 +1353,9 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
# in some way, say Unknown.
if not exhaustive: result = Unknown
of nkCaseStmt:
if containsResult(n[0]): return InitRequired
if containsResult(n.firstSon): return InitRequired
result = InitSkippable
var exhaustive = skipTypes(n[0].typ,
var exhaustive = skipTypes(n.firstSon.typ,
abstractVarRange-{tyTypeDesc}).kind notin {tyFloat..tyFloat128, tyString, tyCstring}
for i in 1..<n.len:
let it = n[i]
@@ -1365,7 +1365,7 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
of nkWhileStmt:
# some dubious code can assign the result in the 'while'
# condition and that would be fine. Everything else isn't:
result = allPathsAsgnResult(p, n[0])
result = allPathsAsgnResult(p, n.firstSon)
if result == Unknown:
result = allPathsAsgnResult(p, n[1])
# we cannot assume that the 'while' loop is really executed at least once:
@@ -1389,19 +1389,19 @@ proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
# assignment this is not good enough! The only pattern we allow for
# is 'finally: result = x'
result = InitSkippable
allPathsInBranch(n[0])
allPathsInBranch(n.firstSon)
for i in 1..<n.len:
if n[i].kind == nkFinally:
result = allPathsAsgnResult(p, n[i].lastSon)
else:
allPathsInBranch(n[i].lastSon)
of nkCallKinds:
if canRaiseDisp(p, n[0]) or
(n[0].kind == nkSym and sfNoReturn in n[0].sym.flags):
if canRaiseDisp(p, n.firstSon) or
(n.firstSon.kind == nkSym and sfNoReturn in n.firstSon.sym.flags):
# requires initializations when encountering unreachable code
result = InitRequired
elif n[0].kind == nkSym and
n[0].sym.magic in {mUnaryMinusI..mAbsI, mAddI..mPred} and
elif n.firstSon.kind == nkSym and
n.firstSon.sym.magic in {mUnaryMinusI..mAbsI, mAddI..mPred} and
optOverflowCheck in p.config.options:
# arithmetic operations may raise exceptions
result = InitRequired