From 0206aa334c59e8b8f0932260c250509908fefd58 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 4 Aug 2026 15:18:34 +0200 Subject: [PATCH] =?UTF-8?q?backend:=20refactorings=20so=20that=20eventuall?= =?UTF-8?q?y=20it=20can=20run=20on=20BIF=20directly=20w=E2=80=A6=20(#25959?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …ithout PNode constructions; also added bif2nif.nim inspection tool --- compiler/astdef.nim | 10 +++ compiler/ccgcalls.nim | 104 +++++++++++----------- compiler/ccgexprs.nim | 193 +++++++++++++++++++++-------------------- compiler/ccgstmts.nim | 194 +++++++++++++++++++++--------------------- compiler/ccgtypes.nim | 36 ++++---- compiler/cgen.nim | 44 +++++----- 6 files changed, 294 insertions(+), 287 deletions(-) diff --git a/compiler/astdef.nim b/compiler/astdef.nim index d2af6a9064..eb0e49da64 100644 --- a/compiler/astdef.nim +++ b/compiler/astdef.nim @@ -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.. 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) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index af67c19e10..dc62e7c818 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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..= 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.. 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.. 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.. 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.. 0: var tmp = getTempName(m) & "_" & $n.len genTNimNodeArray(m, tmp, n.len) - for i in 0.. 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.. 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.. 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..