diff --git a/compiler/ast/ast.nim b/compiler/ast/ast.nim index 0f03fa848f4..e6f37cb39b1 100644 --- a/compiler/ast/ast.nim +++ b/compiler/ast/ast.nim @@ -34,7 +34,7 @@ type Gconfig = object ## we put comments in a side channel to avoid increasing `sizeof(TNode)`, ## which reduces memory usage given that `PNode` is the most allocated ## type by far. - comments: Table[int, string] # nodeId => comment + comments: Table[NodeId, string] # nodeId => comment useIc*: bool var gconfig {.threadvar.}: Gconfig @@ -319,6 +319,7 @@ proc discardSons*(father: PNode) type Indexable = PNode | PType proc len*(n: Indexable): int {.inline.} = + ## number of children, unsafe if called on leaf nodes, see `safeLen` result = n.sons.len proc safeLen*(n: PNode): int {.inline.} = @@ -326,15 +327,22 @@ proc safeLen*(n: PNode): int {.inline.} = if n.kind in {nkNone..nkNilLit}: result = 0 else: result = n.len -proc add*(father, son: Indexable) = - assert son != nil - father.sons.add(son) +proc safeArrLen*(n: PNode): int {.inline.} = + ## works for array-like objects (strings passed as openArray in VM). + if n.kind in {nkStrLit..nkTripleStrLit}: result = n.strVal.len + elif n.kind in {nkNone..nkFloat128Lit}: result = 0 + else: result = n.len proc addAllowNil*(father, son: Indexable) {.inline.} = father.sons.add(son) +proc add*(father, son: Indexable) {.inline.} = + assert son != nil + addAllowNil(father, son) + template `[]`*(n: Indexable, i: int): Indexable = n.sons[i] -template `[]=`*(n: Indexable, i: int; x: Indexable) = n.sons[i] = x +template `[]=`*(n: Indexable, i: int; x: Indexable) = + n.sons[i] = x template `[]`*(n: Indexable, i: BackwardsIndex): Indexable = n[n.len - i.int] template `[]=`*(n: Indexable, i: BackwardsIndex; x: Indexable) = n[n.len - i.int] = x @@ -366,19 +374,46 @@ proc getDeclPragma*(n: PNode): PNode = result = n[0][1] else: # support as needed for `nkIdentDefs` etc. - result = nil + result = nilPNode if result != nil: assert result.kind == nkPragma, $(result.kind, n.kind) -const invalidNodeId* = 0 -var gNodeId: int - when defined(useNodeIds): - const nodeIdToDebug* = -1 # 2322968 + const nodeIdToDebug* = NodeId -1 # 2322968 -template setNodeId() = - inc gNodeId - result.id = gNodeId +template newNodeImpl(kind: TNodeKind, info2: TLineInfo) = + # result = PNode(kind: kind, info: info2) + {.cast(noSideEffect).}: + let + nodeId = state.nextNodeId() + nodeIdx = nodeId.idx + state.nodeList.add NodeData(kind: kind) + state.nodeInf.add info2 + state.nodeFlag.add {} + case extraDataKind(kind): + of ExtraDataInt: + state.nodeInt.add 0 + state.nodeList[nodeIdx].extra = ExtraDataId state.nodeInt.len + of ExtraDataFloat: + state.nodeFlt.add 0 + state.nodeList[nodeIdx].extra = ExtraDataId state.nodeFlt.len + of ExtraDataString: + state.nodeStr.add "" + state.nodeList[nodeIdx].extra = ExtraDataId state.nodeStr.len + of ExtraDataSymbol: + state.nodeSym.add nil + state.nodeList[nodeIdx].extra = ExtraDataId state.nodeSym.len + of ExtraDataIdentifier: + state.nodeIdt.add nil + state.nodeList[nodeIdx].extra = ExtraDataId state.nodeIdt.len + of ExtraDataAst, ExtraDataNone: + state.astData.add @[] + state.nodeList[nodeIdx].extra = ExtraDataId state.astData.len + discard + + result = PNode(id: nodeId) + +template checkNodeIdForDebug() = when defined(useNodeIds): if result.id == nodeIdToDebug: echo "KIND ", result.kind @@ -386,16 +421,17 @@ template setNodeId() = func newNodeI*(kind: TNodeKind, info: TLineInfo): PNode = ## new node with line info, no type, and no children - result = PNode(kind: kind, info: info, reportId: emptyReportId) + newNodeImpl(kind, info) {.cast(noSideEffect).}: - setNodeId() - when false: - # this would add overhead, so we skip it; it results in a small amount of leaked entries - # for old PNode that gets re-allocated at the same address as a PNode that - # has `nfHasComment` set (and an entry in that table). Only `nfHasComment` - # should be used to test whether a PNode has a comment; gconfig.comments - # can contain extra entries for deleted PNode's with comments. - gconfig.comments.del(result.id) + checkNodeIdForDebug() + when defined(nimsuggest): + # this would add overhead, so we skip it; it results in a small amount of + # leaked entries for old PNode that gets re-allocated at the same address + # as a PNode that has `nfHasComment` set (and an entry in that table). + # Only `nfHasComment` should be used to test whether a PNode has a + # comment; gconfig.comments can contain extra entries for deleted PNode's + # with comments. + gconfig.comments.del(result.id) proc newNode*(kind: TNodeKind): PNode = ## new node with unknown line info, no type, and no children @@ -418,6 +454,11 @@ proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType, children: int): PN if children > 0: newSeq(result.sons, children) +proc newErrorNodeIT*(rep: ReportId, info: TLineInfo, typ: PType): PNode = + ## new node with line info, type, report, and no children + result = newNodeIT(nkError, info, typ) + result.reportId = rep + proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode = result = newNode(kind) if children.len > 0: @@ -802,14 +843,43 @@ proc delSon*(father: PNode, idx: int) = for i in idx.." + + else: + "" +#------------------------------------------------------------------------------ +# DOD AST Draft - Start +#------------------------------------------------------------------------------ + +# xxx: need this stuff for distincts +proc hash*(n: NodeId): Hash {.borrow.} +proc `==`*(a, b: NodeId): bool {.borrow.} +proc cmp*(a, b: NodeId): int = cmp(a.int, b.int) +proc `$`*(n: NodeId): string {.inline.} = $(int(n)) +# proc hash*(n: InfoId): Hash {.borrow.} +# proc `==`*(a, b: InfoId): bool {.borrow.} +# proc cmp*(a, b: InfoId): int = cmp(a.int, b.int) +proc cmp*(a, b: PSym): int = cmp(cast[int](a), cast[int](b)) +proc `==`*(a, b: ExtraDataId): bool {.borrow.} + +func extraDataKind*(k: TNodeKind): ExtraDataKind {.inline.} = + case k + of nkCharLit..nkUInt64Lit: ExtraDataInt + of nkFloatLit..nkFloat128Lit: ExtraDataFloat + of nkStrLit..nkTripleStrLit: ExtraDataString + of nkSym: ExtraDataSymbol + of nkIdent: ExtraDataIdentifier + else: ExtraDataAst + +const + # unknownLineInfoId = InfoId 0 + nilNodeId* = NodeId 0 + nilExtraDataId* = ExtraDataId 0 + +const nilPNode* = PNode(id: nilNodeId) + +func `==`*(a, b: PNode): bool {.inline.} = + a.id == b.id +func `==`*(a: PNode, b: typeof(nil)): bool {.inline.} = + a.id == nilNodeId +func `==`*(a: typeof(nil), b: PNode): bool {.inline.} = + b.id == nilNodeId +func isNil*(a: PNode): bool {.inline.} = + a.id == nilNodeId + +var state* = State( + # xxx: set good default capacity based on the system lib alone + ) + +func isBad*(n: PNode): bool {.inline, deprecated: "for debugging".} = + return n.id != nilNodeId +func isNilOrBad*(n: PNode): bool {.inline, deprecated: "for debugging".} = + return n.id != nilNodeId + +proc nextNodeId*(s: State): NodeId {.inline.} = + NodeId state.nodeList.len + 1 + +func idx*(n: NodeId): int {.inline.} = + ## internal NodeId to node index + # assert n != nilNodeId, "attempting to get an idx of a nil node" + n.int - 1 +func idx*(n: PNode): int {.inline.} = n.id.idx + ## internal PNode to node index + +proc extraId*(n: PNode): ExtraDataId {.inline.} = + ## quick access to the ExtraDataId for a node + state.nodeList[n.idx].extra +func idx*(e: ExtraDataId): int {.inline.} = + ## internal ExtraDataId to node extra data index + # assert e != nilExtraDataId, "attempting to get an idx of a nil extra data id" + e.int - 1 +proc extraIdx*(n: PNode): int {.inline.} = n.extraId.idx + ## quick access to the extra data index for a node + +func id*(n: PNode): NodeId {.inline.} = n.id + +proc kind*(n: PNode): TNodeKind = + {.cast(noSideEffect).}: + result = state.nodeList[n.idx].kind + +proc typ*(n: PNode): PType {.inline.} = + {.cast(noSideEffect).}: + result = state.nodeTyp.getOrDefault(n.id, nil) +proc `typ=`*(n: PNode, t: PType) {.inline.} = + state.nodeTyp[n.id] = t + +proc info*(n: PNode): var TLineInfo {.inline.} = + {.cast(noSideEffect).}: + result = state.nodeInf[n.idx] +proc `info=`*(n: PNode, info: TLineInfo) {.inline.} = + state.nodeInf[n.idx] = info + +proc flags*(n: PNode): var TNodeFlags {.inline.} = + state.nodeFlag[n.idx] +proc `flags=`*(n: PNode, flags: TNodeFlags) {.inline.} = + state.nodeFlag[n.idx] = flags + +proc intVal*(n: PNode): var BiggestInt {.inline.} = + # assert n.kind in {nkCharLit..nkUInt64Lit}, "not an integer, id: " & $n.id + {.cast(noSideEffect).}: + result = state.nodeInt[n.extraIdx] +proc `intVal=`*(n: PNode, v: BiggestInt) {.inline.} = + # assert n.kind in {nkCharLit..nkUInt64Lit}, "not an integer, id: " & $n.id + if n.extraId == nilExtraDataId: + state.nodeInt.add v + state.nodeList[n.idx].extra = ExtraDataId state.nodeInt.len + else: + state.nodeInt[n.extraId.idx] = v + +proc floatVal*(n: PNode): var BiggestFloat {.inline.} = + # assert n.kind in {nkFloatLit..nkFloat128Lit}, "not a float, id: " & $n.id + {.cast(noSideEffect).}: + result = state.nodeFlt[n.extraId.idx] +proc `floatVal=`*(n: PNode, v: BiggestFloat) {.inline.} = + # assert n.kind in {nkFloatLit..nkFloat128Lit}, "not a float, id: " & $n.id + if n.extraId == nilExtraDataId: + state.nodeFlt.add v + state.nodeList[n.idx].extra = ExtraDataId state.nodeFlt.len + else: + state.nodeFlt[n.extraId.idx] = v + +proc strVal*(n: PNode): var string {.inline.} = + # assert n.kind in {nkStrLit..nkTripleStrLit}, "not a string, id: " & $n.id + {.cast(noSideEffect).}: + result = state.nodeStr[n.extraId.idx] +proc `strVal=`*(n: PNode, v: string) {.inline.} = + # assert n.kind in {nkStrLit..nkTripleStrLit}, "not a string, id: " & $n.id + if n.extraId == nilExtraDataId: + state.nodeStr.add v + state.nodeList[n.idx].extra = ExtraDataId state.nodeStr.len + else: + state.nodeStr[n.extraId.idx] = v + +proc sym*(n: PNode): PSym {.inline.} = + # assert n.kind == nkSym, "not a symbol, id: " & $n.id & " and kind: " & $n.kind + {.cast(noSideEffect).}: + result = state.nodeSym[n.extraId.idx] +proc `sym=`*(n: PNode, sym: PSym) {.inline.} = + # assert n.kind == nkSym, "not a symbol, id: " & $n.id + {.cast(noSideEffect).}: + if n.extraId == nilExtraDataId: + state.nodeSym.add sym + state.nodeList[n.idx].extra = ExtraDataId state.nodeSym.len + else: + state.nodeSym[n.extraId.idx] = sym + +proc ident*(n: PNode): PIdent {.inline.} = + assert n.kind == nkIdent, "not an ident, id: " & $n.id + {.cast(noSideEffect).}: + result = state.nodeIdt[n.extraId.idx] +proc `ident=`*(n: PNode, ident: PIdent) {.inline.} = + assert n.kind == nkIdent, "not an ident, id: " & $n.id + {.cast(noSideEffect).}: + if n.extraId == nilExtraDataId: + state.nodeIdt.add ident + state.nodeList[n.idx].extra = ExtraDataId state.nodeIdt.len + else: + state.nodeIdt[n.extraId.idx] = ident + +const haveNoSons = { + nkCharLit..nkUInt64Lit, + nkFloatLit..nkFloat128Lit, + nkStrLit..nkTripleStrLit, + nkSym, + nkIdent + } + +proc initSons*(n: PNode) {.inline.} = + ## reset sons storage, this shouldn't be needed if lifetimes were clarified + ## and the VM didn't abuse nodes as it does. + if n.extraId == nilExtraDataId: + state.astData.add @[] + state.nodeList[n.idx].extra = ExtraDataId state.astData.len + +proc sons*(n: PNode): var TNodeSeq {.inline.} = + # assert n.kind notin haveNoSons, "not a parent, id: " & $n.id + {.cast(noSideEffect).}: + # assert n.id.int <= state.nodeList.len, "invalid node id: " & $n.id.int + initSons(n) + result = state.astData[n.extraId.idx] +proc `sons=`*(n: PNode, sons: TNodeSeq) = + # assert n.kind notin haveNoSons, "not a parent, id: " & $n.id + # assert n.id.int <= state.nodeList.len, "invalid node id: " & $n.id.int + {.cast(noSideEffect).}: + state.astData[n.extraIdx] = sons + +proc reportId*(n: PNode): ReportId {.inline.} = + state.nodeRpt.getOrDefault(n.id, emptyReportId) +proc `reportId=`*(n: PNode, id: ReportId) {.inline.} = + state.nodeRpt[n.id] = id + +proc idToNode*(id: NodeId): PNode {.inline.} = + # assert id.int <= state.nodeList.len, "invalid node id: " & $id.int + case id + of nilNodeId: nilPNode + else: PNode(id: id) + +#------------------------------------------------------------------------------ +# DOD AST Draft - End +#------------------------------------------------------------------------------ type EffectsCompat* = enum @@ -1113,18 +1387,3 @@ type # overload resolution. TExprFlags* = set[TExprFlag] - - -const emptyReportId* = ReportId(0) - -func `==`*(id1, id2: ReportId): bool = uint32(id1) == uint32(id2) -func `<`*(id1, id2: ReportId): bool = uint32(id1) < uint32(id2) - -func isEmpty*(id: ReportId): bool = id == emptyReportId - -func `$`*(id: ReportId): string = - if id.isEmpty: - "" - - else: - "" diff --git a/compiler/ast/astalgo.nim b/compiler/ast/astalgo.nim index 9376a6cb1bf..0dd0483d923 100644 --- a/compiler/ast/astalgo.nim +++ b/compiler/ast/astalgo.nim @@ -89,7 +89,7 @@ proc sameValue*(a, b: PNode): bool = #InternalError(a.info, "SameValue") discard -proc leValue*(a, b: PNode): bool = +func leValue*(a, b: PNode): bool = # a <= b? result = false case a.kind @@ -501,7 +501,7 @@ proc idNodeTableGet(t: TIdNodeTable, key: PIdObj): PNode = var index: int index = idNodeTableRawGet(t, key) if index >= 0: result = t.data[index].val - else: result = nil + else: result = nilPNode proc idNodeTableRawInsert(data: var TIdNodePairSeq, key: PIdObj, val: PNode) = var h: Hash diff --git a/compiler/ast/enumtostr.nim b/compiler/ast/enumtostr.nim index 12b206321e6..72dc87c483c 100644 --- a/compiler/ast/enumtostr.nim +++ b/compiler/ast/enumtostr.nim @@ -52,7 +52,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener proc searchObjCaseImpl(obj: PNode; field: PSym): PNode = case obj.kind of nkSym: - result = nil + result = nilPNode of nkElse, nkOfBranch: result = searchObjCaseImpl(obj.lastSon, field) else: diff --git a/compiler/ast/errorhandling.nim b/compiler/ast/errorhandling.nim index a1b23adf964..e26bdef5ff0 100644 --- a/compiler/ast/errorhandling.nim +++ b/compiler/ast/errorhandling.nim @@ -49,11 +49,11 @@ proc errorSubNode*(n: PNode): PNode = ## find the first error node, or nil, under `n` using a depth first traversal case n.kind of nkEmpty..nkNilLit: - result = nil + result = nilPNode of nkError: result = n else: - result = nil + result = nilPNode for s in n.items: if s.isNil: continue result = errorSubNode(s) @@ -85,11 +85,10 @@ proc newError*( assert wrongNode != nil, "can't have a nil node for `wrongNode`" assert not report.isEmpty(), $report - result = PNode( - kind: nkError, - info: wrongNode.info, - typ: newType(tyError, ItemId(module: -2, item: -1), nil), - reportId: report + result = newErrorNodeIT( + report, + wrongNode.info, + newType(tyError, ItemId(module: -2, item: -1), nil) ) addInNimDebugUtilsError(conf, wrongNode, result) diff --git a/compiler/ast/filters.nim b/compiler/ast/filters.nim index 62c0a36978c..ae8e72f3d06 100644 --- a/compiler/ast/filters.nim +++ b/compiler/ast/filters.nim @@ -32,7 +32,7 @@ proc invalidPragma(conf: ConfigRef; n: PNode) = conf.localReport(n.info, reportAst(rsemNodeNotAllowed, n)) proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode = - result = nil + result = nilPNode if n.kind in {nkEmpty..nkNilLit}: return for i in 1.. 1: lineF(p, "}$n", []) else: var orExpr: Rope = nil - var excAlias: PNode = nil + var excAlias: PNode = nilPNode useMagic(p, "isObj") for j in 0..= 0: options.setConfigVar(conf, switch, arg) else: invalidCmdLineOption(conf, pass, switch, info) diff --git a/compiler/front/msgs.nim b/compiler/front/msgs.nim index 39327287ab8..93b2f59a11d 100644 --- a/compiler/front/msgs.nim +++ b/compiler/front/msgs.nim @@ -567,7 +567,7 @@ template localReport*(conf: ConfigRef, report: Report) = proc semReportCountMismatch*( kind: ReportKind, expected, got: distinct SomeInteger, - node: PNode = nil, + node: PNode = nilPNode, ): SemReport = result = SemReport(kind: kind, ast: node) result.countMismatch = (toInt128(expected), toInt128(got)) diff --git a/compiler/front/options.nim b/compiler/front/options.nim index 98f98feb067..0ee1c14b12d 100644 --- a/compiler/front/options.nim +++ b/compiler/front/options.nim @@ -499,7 +499,7 @@ proc canReport*(conf: ConfigRef, id: ReportId): bool = ## Check whether report with given ID can actually be written out, or it ## has already been seen. This check is used to prevent multiple reports ## from the `nkError` node. - id notin conf.m.writtenSemReports + true or id notin conf.m.writtenSemReports proc canReport*(conf: ConfigRef, node: PNode): bool = ## Check whether `nkError` node can be reported diff --git a/compiler/ic/dce.nim b/compiler/ic/dce.nim index b40c21abb26..4566209e443 100644 --- a/compiler/ic/dce.nim +++ b/compiler/ic/dce.nim @@ -61,7 +61,7 @@ proc followLater(c: var AliveContext; g: PackedModuleGraph; module: int; item: i if body != emptyNodeId: let opt = g[module].fromDisk.syms[item].options if g[module].fromDisk.syms[item].kind in routineKinds: - body = NodeId ithSon(g[module].fromDisk.bodies, NodePos body, bodyPos) + body = packed_ast.NodeId ithSon(g[module].fromDisk.bodies, NodePos body, bodyPos) c.stack.add((module, opt, NodePos(body))) when false: diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim index 58f7202cc2d..3eac7a79799 100644 --- a/compiler/ic/ic.nim +++ b/compiler/ic/ic.nim @@ -758,7 +758,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; tree: PackedTree; n: NodePos): PNode = let k = n.kind if k == nkNilRodNode: - return nil + return nilPNode when false: echo "loading node ", c.config $ translateLineInfo(c, g, thisModule, n.info) result = newNodeIT(k, translateLineInfo(c, g, thisModule, n.info), @@ -784,7 +784,7 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; let (n1, n2) = sons2(tree, n) assert n1.kind == nkInt32Lit assert n2.kind == nkInt32Lit - transitionNoneToSym(result) + result.transitionNoneToSym() result.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)) else: for n0 in sonsReadonly(tree, n): @@ -812,7 +812,7 @@ proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: if i != bodyPos: result.add loadNodes(c, g, thisModule, tree, n0) else: - result.addAllowNil nil + result.addAllowNil nilPNode inc i proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; diff --git a/compiler/modules/magicsys.nim b/compiler/modules/magicsys.nim index 503bfd5b6df..e373c63bfbc 100644 --- a/compiler/modules/magicsys.nim +++ b/compiler/modules/magicsys.nim @@ -122,7 +122,7 @@ proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType = proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} = if t.n != nil and t.kind in {tyInt, tyFloat}: result = copyType(t, nextTypeId(id), t.owner) - result.n = nil + result.n = nilPNode else: result = t diff --git a/compiler/modules/modules.nim b/compiler/modules/modules.nim index 447f4e2f761..ad5fd6d37f3 100644 --- a/compiler/modules/modules.nim +++ b/compiler/modules/modules.nim @@ -147,7 +147,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags, fr result.flags.excl sfDirty # reset module fields: initStrTables(graph, result) - result.ast = nil + result.ast = nilPNode processModuleAux("import(dirty)") graph.markClientsDirty(fileIdx) diff --git a/compiler/sem/closureiters.nim b/compiler/sem/closureiters.nim index 73487cc4808..74e32855f16 100644 --- a/compiler/sem/closureiters.nim +++ b/compiler/sem/closureiters.nim @@ -473,7 +473,7 @@ proc newNotCall(g: ModuleGraph; e: PNode): PNode = result = newTree(nkCall, newSymNode(g.getSysMagic(e.info, "not", mNot), e.info), e) result.typ = g.getSysType(e.info, tyBool) -proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = +proc lowerStmtListExprs(ctx: var Ctx, n: var PNode, needsSplit: var bool): PNode = result = n case n.kind of nkSkip: @@ -995,7 +995,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode if exceptBody.kind != nkEmpty: ctx.curExcHandlingState = finallyIdx - let realExceptIdx = ctx.newState(exceptBody, nil) + let realExceptIdx = ctx.newState(exceptBody, nilPNode) assert(realExceptIdx == -exceptIdx) ctx.curExcHandlingState = oldExcHandlingState @@ -1279,7 +1279,7 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode = proc deleteEmptyStates(ctx: var Ctx) = let goOut = newTree(nkGotoState, ctx.g.newIntLit(TLineInfo(), -1)) - ctx.exitStateIdx = ctx.newState(goOut, nil) + ctx.exitStateIdx = ctx.newState(goOut, nilPNode) # Apply new state indexes and mark unused states with -1 var iValid = 0 @@ -1429,7 +1429,7 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n: #echo "transformed into ", n #var n = n.toStmtList - discard ctx.newState(n, nil) + discard ctx.newState(n, nilPNode) let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1)) var ns = false diff --git a/compiler/sem/guards.nim b/compiler/sem/guards.nim index 6530c4efbc6..725e609acb8 100644 --- a/compiler/sem/guards.nim +++ b/compiler/sem/guards.nim @@ -113,7 +113,7 @@ proc swapArgs(fact: PNode, newOp: PSym): PNode = result[2] = fact[1] proc neg(n: PNode; o: Operators): PNode = - if n == nil: return nil + if n == nil: return nilPNode case n.getMagic of mNot: result = n[1] @@ -123,7 +123,7 @@ proc neg(n: PNode; o: Operators): PNode = of someLe: result = swapArgs(n, o.opLt) of mInSet: - if n[1].kind != nkCurly: return nil + if n[1].kind != nkCurly: return nilPNode let t = n[2].typ.skipTypes(abstractInst) result = newNodeI(nkCall, n.info, 3) result[0] = n[0] @@ -139,7 +139,7 @@ proc neg(n: PNode; o: Operators): PNode = else: # not ({2, 3, 4}.contains(x)) x != 2 and x != 3 and x != 4 # XXX todo - result = nil + result = nilPNode of mOr: # not (a or b) --> not a and not b let @@ -304,7 +304,7 @@ proc canon*(n: PNode; o: Operators): PNode = reassociation(o.opAdd.buildCall(y, x[2]), o)) of someAdd: # Rule A: - let plus = negate(y, x[2], nil, o).reassociation(o) + let plus = negate(y, x[2], nilPNode, o).reassociation(o) if plus != nil: result = buildCall(result[0].sym, x[1], plus) else: discard elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and @@ -315,7 +315,7 @@ proc canon*(n: PNode; o: Operators): PNode = result = buildCall(result[0].sym, y[1], reassociation(o.opAdd.buildCall(x, y[2]), o)) of someAdd: - let plus = negate(x, y[2], nil, o).reassociation(o) + let plus = negate(x, y[2], nilPNode, o).reassociation(o) # ensure that Rule A will not trigger afterwards with the # additional 'not isLetLocation' constraint: if plus != nil and not isLetLocation(x, true): @@ -898,7 +898,7 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication = let fact = m.s[i] if fact != nil and fact.getMagic in someLe: # mark as used: - m.s[i] = nil + m.s[i] = nilPNode # i <= len-100 # i <=? len-1 # --> true if (len-100) <= (len-1) diff --git a/compiler/sem/injectdestructors.nim b/compiler/sem/injectdestructors.nim index 7ae0c8eb392..62a2ce6b1a3 100644 --- a/compiler/sem/injectdestructors.nim +++ b/compiler/sem/injectdestructors.nim @@ -104,7 +104,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; isDecl = false): PNod import sets, hashes -proc hash(n: PNode): Hash = hash(cast[pointer](n)) +proc hash(n: PNode): Hash = hash(n.id) proc aliasesCached(cache: var Table[(PNode, PNode), AliasKind], obj, field: PNode): AliasKind = let key = (obj, field) @@ -327,7 +327,7 @@ proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode proc genDestroy(c: var Con; dest: PNode): PNode = let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink}) - result = c.genOp(t, attachedDestructor, dest, nil) + result = c.genOp(t, attachedDestructor, dest, nilPNode) proc canBeMoved(c: Con; t: PType): bool {.inline.} = let t = t.skipTypes({tyGenericInst, tyAlias, tySink}) @@ -545,7 +545,7 @@ proc cycleCheck(n: PNode; c: var Con) = return var x = n[0] - var field: PNode = nil + var field: PNode = nilPNode while true: if x.kind == nkDotExpr: field = x[1] diff --git a/compiler/sem/lookups.nim b/compiler/sem/lookups.nim index 3f9505de3eb..00d3edd7cce 100644 --- a/compiler/sem/lookups.nim +++ b/compiler/sem/lookups.nim @@ -68,8 +68,8 @@ proc considerQuotedIdent2*(c: PContext; n: PNode): PIdentResult = result = case n.kind - of nkIdent: (ident: n.ident, errNode: nil) - of nkSym: (ident: n.sym.name, errNode: nil) + of nkIdent: (ident: n.ident, errNode: nilPNode) + of nkSym: (ident: n.sym.name, errNode: nilPNode) of nkAccQuoted: case n.len of 0: (ident: ic.getNotFoundIdent(), errNode: n) @@ -90,10 +90,10 @@ proc considerQuotedIdent2*(c: PContext; n: PNode): PIdentResult = if error: (ident: ic.getNotFoundIdent(), errNode: n) else: - (ident: getIdent(c.cache, id), errNode: nil) + (ident: getIdent(c.cache, id), errNode: nilPNode) of nkOpenSymChoice, nkClosedSymChoice: if n[0].kind == nkSym: - (ident: n[0].sym.name, errNode: nil) + (ident: n[0].sym.name, errNode: nilPNode) else: (ident: ic.getNotFoundIdent(), errNode: n) else: @@ -110,7 +110,7 @@ proc noidentError(conf: ConfigRef; n, origin: PNode) = wrongNode: origin )) -proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent = +proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nilPNode): PIdent = ## Retrieve a PIdent from a PNode, taking into account accent nodes. ## ``origin`` can be nil. If it is not nil, it is used for a better ## error message. @@ -642,7 +642,7 @@ proc newQualifiedLookUpError(c: PContext, ident: PIdent, info: TLineInfo, err: P result.ast = err proc errorExpectedIdentifier( - c: PContext, ident: PIdent, n: PNode, exp: PNode = nil + c: PContext, ident: PIdent, n: PNode, exp: PNode = nilPNode ): PSym {.inline.} = ## create an error symbol for non-identifier in identifier position within an ## expression (`exp`). non-nil `exp` leads to better error messages. @@ -748,7 +748,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = amb = false (ident, errNode) = considerQuotedIdent2(c, n) if isNotFound(c.cache, ident): - let errExprCtx = if errNode != n: n else: nil + let errExprCtx = if errNode != n: n else: nilPNode ## expression within which the error occurred result = errorExpectedIdentifier(c, ident, errNode, errExprCtx) elif checkModule in flags: @@ -816,7 +816,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym = if m != nil and m.kind == skModule: var ident: PIdent = nil - errNode: PNode = nil + errNode: PNode = nilPNode if n[1].kind == nkIdent: ident = n[1].ident elif n[1].kind == nkAccQuoted: diff --git a/compiler/sem/lowerings.nim b/compiler/sem/lowerings.nim index 3cd62475d6f..bbfddf2e395 100644 --- a/compiler/sem/lowerings.nim +++ b/compiler/sem/lowerings.nim @@ -300,7 +300,7 @@ proc genDeref*(n: PNode; k = nkHiddenDeref): PNode = proc callCodegenProc*(g: ModuleGraph; name: string; info: TLineInfo = unknownLineInfo; - arg1, arg2, arg3, optionalArgs: PNode = nil): PNode = + arg1, arg2, arg3, optionalArgs: PNode = nilPNode): PNode = result = newNodeI(nkCall, info) let sym = magicsys.getCompilerProc(g, name) if sym == nil: diff --git a/compiler/sem/nilcheck.nim b/compiler/sem/nilcheck.nim index 553788a15a9..4238f33e550 100644 --- a/compiler/sem/nilcheck.nim +++ b/compiler/sem/nilcheck.nim @@ -392,7 +392,6 @@ proc aliasSet(ctx: NilCheckerContext, map: NilMap, index: ExprIndex): IntSet = result = map.sets[map.setIndices[index]] - proc store( map: NilMap, ctx: NilCheckerContext, @@ -400,9 +399,8 @@ proc store( value: Nilability, kind: NilTransition, info: TLineInfo, - node: PNode = nil + node: PNode = nilPNode ) = - if index == noExprIndex: return map.expressions[index] = value diff --git a/compiler/sem/passes.nim b/compiler/sem/passes.nim index 46039cea953..a944c747d8d 100644 --- a/compiler/sem/passes.nim +++ b/compiler/sem/passes.nim @@ -78,7 +78,7 @@ proc openPasses(g: ModuleGraph; a: var TPassContextArray; else: a[i] = nil proc closePasses(graph: ModuleGraph; a: var TPassContextArray) = - var m: PNode = nil + var m: PNode = nilPNode for i in 0.. 0: result = transformSpawnSons(g, idgen, owner, n, barrier) diff --git a/compiler/sem/sempass2.nim b/compiler/sem/sempass2.nim index ac356607c19..2d59e319157 100644 --- a/compiler/sem/sempass2.nim +++ b/compiler/sem/sempass2.nim @@ -671,8 +671,8 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = discard proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) = - addRaiseEffect(tracked, createRaise(tracked.graph, n), nil) - addTag(tracked, createTag(tracked.graph, n), nil) + addRaiseEffect(tracked, createRaise(tracked.graph, n), nilPNode) + addTag(tracked, createTag(tracked.graph, n), nilPNode) let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel else: op.lockLevel #if lockLevel == UnknownLockLevel: @@ -1092,7 +1092,7 @@ proc track(tracked: PEffects, n: PNode) = # A `raise` with no arguments means we're going to re-raise the exception # being handled or, if outside of an `except` block, a `ReraiseDefect`. # Here we add a `Exception` tag in order to cover both the cases. - addRaiseEffect(tracked, createRaise(tracked.graph, n), nil) + addRaiseEffect(tracked, createRaise(tracked.graph, n), nilPNode) of nkCallKinds: trackCall(tracked, n) of nkDotExpr: @@ -1339,7 +1339,7 @@ proc checkRaisesSpec( spec, real: PNode, hints: bool, effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.}, - hintsArg: PNode = nil + hintsArg: PNode = nilPNode ) = # check that any real exception is listed in 'spec'; mark those as used; # report any unused exception diff --git a/compiler/sem/semstmts.nim b/compiler/sem/semstmts.nim index 045d948f99f..f916c6fa39c 100644 --- a/compiler/sem/semstmts.nim +++ b/compiler/sem/semstmts.nim @@ -897,7 +897,7 @@ proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string; case match.kind of skMacro: result = semMacroExpr(c, callExpr, match, flags) of skTemplate: result = semTemplateExpr(c, callExpr, match, flags) - else: result = nil + else: result = nilPNode proc handleForLoopMacro(c: PContext; n: PNode; flags: TExprFlags): PNode = result = handleStmtMacro(c, n, n[^2], "ForLoopStmt", flags) @@ -923,7 +923,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode = case match.kind of skMacro: result = semMacroExpr(c, toExpand, match, flags) of skTemplate: result = semTemplateExpr(c, toExpand, match, flags) - else: result = nil + else: result = nilPNode else: assert r.call.kind == nkError result = r.call # xxx: hope this is nkError @@ -2136,6 +2136,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, maybeAddResult(c, s, n) # semantic checking also needed with importc in case used in VM s.ast[bodyPos] = hloBody(c, semProcBody(c, n[bodyPos])) + # unfortunately we cannot skip this step when in 'system.compiles' # context as it may even be evaluated in 'system.compiles': trackProc(c, s, s.ast[bodyPos]) diff --git a/compiler/sem/semtypes.nim b/compiler/sem/semtypes.nim index 91ad9d32b31..42e0771e9f6 100644 --- a/compiler/sem/semtypes.nim +++ b/compiler/sem/semtypes.nim @@ -66,7 +66,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = identToReplace = addr n[i][0] var v = semConstExpr(c, n[i][1]) - var strVal: PNode = nil + var strVal: PNode = nilPNode case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind of tyTuple: if v.len == 2: @@ -482,9 +482,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = if result.typ.kind != tyGenericParam: # XXX get rid of this hack! var oldInfo = n.info - let oldId = n.id - reset(n[]) - n.id = oldId + n.flags = {} n.transitionNoneToSym() n.sym = result n.info = oldInfo @@ -539,7 +537,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = styleCheckDef(c.config, a[j].info, field) onDef(field.info, field) - if result.n.len == 0: result.n = nil + if result.n.len == 0: result.n = nilPNode if isTupleRecursive(result): localReport(c.config, n.info, reportTyp( rsemIllegalRecursion, result)) @@ -835,7 +833,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, if n == nil: return case n.kind of nkRecWhen: - var branch: PNode = nil # the branch to take + var branch: PNode = nilPNode # the branch to take for i in 0.. ", val - idTablePut(c.bindings, key, val.skipIntLit(c.c.idgen)) - -proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) = +proc initCandidateAux(ctx: PContext, + c: var TCandidate, callee: PType) {.inline.} = c.c = ctx c.exactMatches = 0 c.subtypeMatches = 0 @@ -122,14 +109,31 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) = c.genericMatches = 0 c.state = csEmpty c.callee = callee - c.calleeSym = nil - c.call = nil + c.call = nilPNode c.baseTypeMatch = false c.genericConverter = false c.inheritancePenalty = 0 c.error = SemCallMismatch() + +proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) = + initCandidateAux(ctx, c, callee) + c.calleeSym = nil initIdTable(c.bindings) +proc put(c: var TCandidate, key, val: PType) {.inline.} = + ## Given: proc foo[T](x: T); foo(4) + ## key: 'T' + ## val: 'int' (typeof(4)) + when false: + let old = PType(idTableGet(c.bindings, key)) + if old != nil: + echo "Putting ", typeToString(key), " ", typeToString(val), " and old is ", typeToString(old) + if typeToString(old) == "float32": + writeStackTrace() + if c.c.module.name.s == "temp3": + echo "binding ", key, " -> ", val + idTablePut(c.bindings, key, val.skipIntLit(c.c.idgen)) + proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1) = initCandidate(ctx, c, callee.typ) @@ -1899,7 +1903,7 @@ proc isLValue(c: PContext; n: PNode): bool {.inline.} = proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType, arg: PNode): PNode = - result = nil + result = nilPNode for i in 0.. 1: m.callee.n[1].sym else: nil # current routine parameter - container: PNode = nil # constructed container + container: PNode = nilPNode # constructed container let firstArgBlock = findFirstArgBlock(m, n) while a < n.len: c.openShadowScope @@ -2461,7 +2466,7 @@ proc matchesAux(c: PContext, n: PNode, m: var TCandidate, marker: var IntSet) = container = newNodeIT(nkBracket, n[a].info, arrayConstr(c, arg)) container.add arg setSon(m.call, formal.position + 1, container) - if f != formalLen - 1: container = nil + if f != formalLen - 1: container = nilPNode else: setSon(m.call, formal.position + 1, arg) inc f @@ -2547,7 +2552,7 @@ proc matchesAux(c: PContext, n: PNode, m: var TCandidate, marker: var IntSet) = elif formal.typ.kind != tyVarargs or container == nil: setSon(m.call, formal.position + 1, arg) inc f - container = nil + container = nilPNode else: # we end up here if the argument can be converted into the varargs # formal (e.g. seq[T] -> varargs[T]) but we have already instantiated diff --git a/compiler/sem/spawn.nim b/compiler/sem/spawn.nim index 4a225a94d7c..48920a28b64 100644 --- a/compiler/sem/spawn.nim +++ b/compiler/sem/spawn.nim @@ -134,21 +134,21 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym; var threadLocalBarrier: PSym if barrier != nil: var varSection2 = newNodeI(nkVarSection, barrier.info) - threadLocalBarrier = addLocalVar(g, varSection2, nil, idgen, result, + threadLocalBarrier = addLocalVar(g, varSection2, nilPNode, idgen, result, barrier.typ, barrier) body.add varSection2 body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.info, threadLocalBarrier.newSymNode) var threadLocalProm: PSym if spawnKind == srByVar: - threadLocalProm = addLocalVar(g, varSection, nil, idgen, result, fv.typ, fv) + threadLocalProm = addLocalVar(g, varSection, nilPNode, idgen, result, fv.typ, fv) elif fv != nil: internalAssert( g.config, fv.typ.kind == tyGenericInst, "Expected generic inst type kind, but found " & $fv.typ.kind) - threadLocalProm = addLocalVar(g, varSection, nil, idgen, result, fv.typ, fv) + threadLocalProm = addLocalVar(g, varSection, nilPNode, idgen, result, fv.typ, fv) body.add varSection body.add varInit if fv != nil and spawnKind != srByVar: @@ -298,7 +298,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2]) result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3]) - let threadLocal = addLocalVar(g, varSection, nil, idgen, owner, fieldA.typ, + let threadLocal = addLocalVar(g, varSection, nilPNode, idgen, owner, fieldA.typ, indirectAccess(castExpr, fieldA, n.info), useShallowCopy=true) slice[2] = threadLocal.newSymNode @@ -313,7 +313,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; # the array itself does not need to go through a thread local variable: slice[1] = genDeref(indirectAccess(castExpr, field, n.info)) - let threadLocal = addLocalVar(g, varSection, nil, idgen, owner, fieldB.typ, + let threadLocal = addLocalVar(g, varSection, nilPNode, idgen, owner, fieldB.typ, indirectAccess(castExpr, fieldB, n.info), useShallowCopy=true) slice[3] = threadLocal.newSymNode @@ -325,7 +325,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; field.typ = a.typ objType.addField(field, g.cache, idgen) result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a) - let threadLocal = addLocalVar(g, varSection, nil, idgen, owner, field.typ, + let threadLocal = addLocalVar(g, varSection, nilPNode, idgen, owner, field.typ, indirectAccess(castExpr, field, n.info), useShallowCopy=true) call.add(genDeref(threadLocal.newSymNode)) @@ -341,7 +341,7 @@ proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; call.add(threadLocal.newSymNode) proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExpr: PNode; retType: PType; - barrier, dest: PNode = nil): PNode = + barrier, dest: PNode = nilPNode): PNode = # if 'barrier' != nil, then it is in a 'parallel' section and we # generate quite different code let n = spawnExpr[^2] @@ -424,7 +424,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp setupArgsForParallelism(g, n, objType, idgen, wrapperProc, scratchObj, castExpr, call, varSection, varInit, result) - var barrierAsExpr: PNode = nil + var barrierAsExpr: PNode = nilPNode if barrier != nil: let typ = newType(tyPtr, nextTypeId idgen, owner) typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ) @@ -436,7 +436,7 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier) barrierAsExpr = indirectAccess(castExpr, field, n.info) - var fvField, fvAsExpr: PNode = nil + var fvField, fvAsExpr: PNode = nilPNode if spawnKind == srFlowVar: var field = newSym(skField, getIdent(g.cache, "fv"), nextSymId idgen, owner, n.info, g.config.options) field.typ = retType @@ -461,6 +461,6 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp varSection, varInit, call, barrierAsExpr, fvAsExpr, idgen, spawnKind, wrapperProc) result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapperProc.info, - wrapperProc.newSymNode, genAddrOf(scratchObj.newSymNode, idgen), nil, spawnExpr) + wrapperProc.newSymNode, genAddrOf(scratchObj.newSymNode, idgen), nilPNode, spawnExpr) if spawnKind == srFlowVar: result.add fvField diff --git a/compiler/sem/transf.nim b/compiler/sem/transf.nim index b4268a5a9a8..15cd3d96cc7 100644 --- a/compiler/sem/transf.nim +++ b/compiler/sem/transf.nim @@ -114,7 +114,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode = else: return liftIterSym(c.graph, n, c.idgen, getCurrOwner(c)) elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly: # top level .closure procs are still somewhat supported for 'Nake': - return makeClosure(c.graph, c.idgen, s, nil, n.info) + return makeClosure(c.graph, c.idgen, s, nilPNode, n.info) #elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure: # echo n.info, " come heer for ", c.tooEarly # if not c.tooEarly: @@ -748,7 +748,7 @@ proc transformCase(c: PTransf, n: PNode): PNode = # removes `elif` branches of a case stmt # adds ``else: nil`` if needed for the code generator result = newNodeIT(nkCaseStmt, n.info, n.typ) - var ifs: PNode = nil + var ifs: PNode = nilPNode for it in n: var e = transform(c, it) case it.kind @@ -823,7 +823,7 @@ proc transformCall(c: PTransf, n: PNode): PNode = while (j < n.len): let b = transform(c, n[j]) if not isConstExpr(b): break - a = evalOp(op.magic, n, a, b, nil, c.idgen, c.graph) + a = evalOp(op.magic, n, a, b, nilPNode, c.idgen, c.graph) inc(j) result.add(a) if result.len == 2: result = result[1] @@ -893,7 +893,7 @@ proc commonOptimizations*(g: ModuleGraph; idgen: IdGenerator; c: PSym, n: PNode) while j < args.len: let b = args[j] if not isConstExpr(b): break - a = evalOp(op.magic, result, a, b, nil, idgen, g) + a = evalOp(op.magic, result, a, b, nilPNode, idgen, g) inc(j) result.add(a) if result.len == 2: result = result[1] @@ -1132,7 +1132,7 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; cache: bool): # it is important to transform exactly once to get sym ids and locations right prc.transformedBody = result else: - prc.transformedBody = nil + prc.transformedBody = nilPNode # XXX Rodfile support for transformedBody! proc transformStmt*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode): PNode = diff --git a/compiler/sem/varpartitions.nim b/compiler/sem/varpartitions.nim index c87e5f2079e..7b9f55199c6 100644 --- a/compiler/sem/varpartitions.nim +++ b/compiler/sem/varpartitions.nim @@ -324,7 +324,7 @@ proc pathExpr(node: PNode; owner: PSym): PNode = if it is not a valid path expression. ]# var n = node - result = nil + result = nilPNode while true: case n.kind of nkSym: diff --git a/compiler/tools/suggest.nim b/compiler/tools/suggest.nim index 478b98bef80..47f2e2d886d 100644 --- a/compiler/tools/suggest.nim +++ b/compiler/tools/suggest.nim @@ -59,7 +59,7 @@ const template origModuleName(m: PSym): string = m.name.s proc findDocComment(n: PNode): PNode = - if n == nil: return nil + if n == nil: return nilPNode if n.comment.len > 0: return n if n.kind in {nkStmtList, nkStmtListExpr, nkObjectTy, nkRecList} and n.len > 0: result = findDocComment(n[0]) @@ -334,7 +334,7 @@ proc nameFits(c: PContext, s: PSym, n: PNode): bool = proc argsFit(c: PContext, candidate: PSym, n: PNode): bool = case candidate.kind of OverloadableSyms: - var m = newCandidate(c, candidate, nil) + var m = newCandidate(c, candidate, nilPNode) sigmatch.partialMatch(c, n, m) result = m.state != csNoMatch else: @@ -342,7 +342,7 @@ proc argsFit(c: PContext, candidate: PSym, n: PNode): bool = proc suggestCall(c: PContext, n: PNode, outputs: var Suggestions) = let info = n.info - wholeSymTab(filterSym(it, nil, pm) and nameFits(c, it, n) and argsFit(c, it, n), + wholeSymTab(filterSym(it, nilPNode, pm) and nameFits(c, it, n) and argsFit(c, it, n), ideCon) proc suggestVar(c: PContext, n: PNode, outputs: var Suggestions) = @@ -625,7 +625,7 @@ proc sugExpr(c: PContext, n: PNode, outputs: var Suggestions) = # of the next line, so we check the 'field' is actually on the same # line as the object to prevent this from happening: let prefix = if n.len == 2 and n[1].info.line == n[0].info.line and - not c.config.m.trackPosAttached: n[1] else: nil + not c.config.m.trackPosAttached: n[1] else: nilPNode suggestFieldAccess(c, obj, prefix, outputs) #if optIdeDebug in gGlobalOptions: @@ -633,11 +633,11 @@ proc sugExpr(c: PContext, n: PNode, outputs: var Suggestions) = #writeStackTrace() elif n.kind == nkIdent: let - prefix = if c.config.m.trackPosAttached: nil else: n + prefix = if c.config.m.trackPosAttached: nilPNode else: n info = n.info wholeSymTab(filterSym(it, prefix, pm), ideSug) else: - let prefix = if c.config.m.trackPosAttached: nil else: n + let prefix = if c.config.m.trackPosAttached: nilPNode else: n suggestEverything(c, n, prefix, outputs) proc suggestExprNoCheck*(c: PContext, n: PNode) = @@ -684,7 +684,7 @@ proc suggestStmt*(c: PContext, n: PNode) = proc suggestEnum*(c: PContext; n: PNode; t: PType) = var outputs: Suggestions = @[] - suggestSymList(c, t.n, nil, n.info, outputs) + suggestSymList(c, t.n, nilPNode, n.info, outputs) produceOutput(outputs, c.config) if outputs.len > 0: suggestQuit() @@ -696,7 +696,7 @@ proc suggestSentinel*(c: PContext) = # suggest everything: for (it, scopeN, isLocal) in allSyms(c): var pm: PrefixMatch - if filterSymNoOpr(it, nil, pm): + if filterSymNoOpr(it, nilPNode, pm): outputs.add(symToSuggest(c.graph, it, isLocal = isLocal, ideSug, newLineInfo(c.config.m.trackPos.fileIndex, 0, -1), it.getQuality, PrefixMatch.None, false, scopeN)) diff --git a/compiler/utils/astrepr.nim b/compiler/utils/astrepr.nim index c3ca2ebd3c5..347bedb7c28 100644 --- a/compiler/utils/astrepr.nim +++ b/compiler/utils/astrepr.nim @@ -140,6 +140,19 @@ const treeReprAllFields* = { trfShowSymFlags .. trfShowNodeTypes } ## Set ## of flags to print all fields in all tree ## reprs +const defaultTreeReprFlags* = { + trfShowNodeIds, + trfShowNodeFlags, + trfReportInfo, + trfSkipAuxError +} + treeReprAllFields - { + trfShowNodeLineInfo, + trfShowSymLineInfo, + trfShowSymOptions, +} + +const treeReprCompact* = defaultTreeReprFlags + {trfPackedFields} + const style = ( kind: fgBlue, nilIt: fgRed, @@ -212,7 +225,6 @@ var implicitTReprConf*: TReprConf = defaultTReprConf ## global ## debugging functions that could later be called from `gdb` environment ## (`debugAst`, `debugType`, `debugSym`), or sem execution tracer - const IntTypes = { tyInt, tyInt8, tyInt16, tyInt32, tyInt64, tyFloat, tyFloat32, tyFloat64, tyUInt, tyUInt8, diff --git a/compiler/vm/vm.nim b/compiler/vm/vm.nim index 13b05c85818..b19aa3d6781 100644 --- a/compiler/vm/vm.nim +++ b/compiler/vm/vm.nim @@ -45,7 +45,8 @@ import debugutils, int128, btrees, - bitsets + bitsets, + astrepr ], compiler/sem/[ sighashes, @@ -81,6 +82,7 @@ from std/math import round const traceCode = defined(nimVMDebugExecute) + debugEchoCode* = defined(nimVMDebugGenerate) const errIllegalConvFromXtoY = "illegal conversion from '$1' to '$2'" @@ -101,8 +103,8 @@ proc createStackTrace( result = SemReport(kind: rsemVmStackTrace) # Just leave the exceptions empty, they aren't used anyways - result.currentExceptionA = nil - result.currentExceptionB = nil + result.currentExceptionA = nilPNode + result.currentExceptionB = nilPNode block: var i = sframe @@ -419,7 +421,6 @@ proc writeLoc(h: LocHandle, x: TFullReg, mm: var VmMemoryManager) = of rkNimNode: assert h.typ.kind == akPNode setNodeValue(h, x.nimNode) - of rkRegAddr: # The following code won't work in the vm (until rkRegAddr replaced) # .. code-block:: nim @@ -730,7 +731,7 @@ proc compile(c: var TCtx, s: PSym): int = result = r.start when debugEchoCode: - c.codeListing(s, nil, start = result) + c.codeListing(s, nilPNode, start = result) template handleJmpBack() {.dirty.} = if c.loopIterations <= 0: @@ -973,8 +974,9 @@ proc rawExecute(c: var TCtx, pc: var int, tos: var StackFrameIndex): RegisterInd #echo "NEW RUN ------------------------" while true: #{.computedGoto.} - let instr = c.code[pc] - let ra = instr.regA + let + instr = c.code[pc] + ra = instr.regA when traceCode: template regDescr(r): TRegisterKind = @@ -2588,7 +2590,9 @@ proc rawExecute(c: var TCtx, pc: var int, tos: var StackFrameIndex): RegisterInd rc = instr.regC idx = int(regs[rb+rc-1].intVal) callback = c.callbacks[idx].value - args = VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[ptr UncheckedArray[TFullReg]](addr regs[0]), + args = VmArgs( + ra: ra, rb: rb, rc: rc, + slots: cast[ptr UncheckedArray[TFullReg]](addr regs[0]), currentException: c.currentExceptionA, currentLineInfo: c.debug[pc], typeCache: addr c.typeInfoCache, @@ -2679,7 +2683,7 @@ proc rawExecute(c: var TCtx, pc: var int, tos: var StackFrameIndex): RegisterInd else: raiseVmError(reportStr(rsemVmFieldNotFound, "floatVal")) of opcNodeId: decodeB(rkInt) - regs[ra].intVal = regs[rb].nimNode.id + regs[ra].intVal = regs[rb].nimNode.id.int of opcNGetType: let rb = instr.regB let rc = instr.regC @@ -3350,7 +3354,7 @@ proc unpackResult(r: sink VmGenResult, conf: ConfigRef, node: PNode, start: var ## new `nkError` wrapping `node`. Otherwise, sets `start` to the instruction ## offset given by the result and returns `nil` if r.success: - result = nil + result = nilPNode start = r.start else: let kind = r.report.kind @@ -3374,10 +3378,10 @@ proc execProc*(c: var TCtx; sym: PSym; args: openArray[PNode]): PNode = else: var start: int - result = genProc(c, sym).unpackResult(c.config, nil, start) + result = genProc(c, sym).unpackResult(c.config, nilPNode, start) if unlikely(result != nil): localReport(c.config, result) - return nil + return nilPNode var tos = TStackFrame(prc: sym, comesFrom: 0, next: -1) let maxSlots = sym.offset @@ -3402,7 +3406,7 @@ proc execProc*(c: var TCtx; sym: PSym; args: openArray[PNode]): PNode = mkCallback(c, r): newNodeI(nkEmpty, sym.info) let r = execute(c, start, tos, cb) - result = r.unpackResult(c.config, nil, wrap = false) + result = r.unpackResult(c.config, nilPNode, wrap = false) else: localReport(c.config, sym.info, reportSym(rsemVmCallingNonRoutine, sym)) @@ -3417,7 +3421,7 @@ proc evalStmt(c: var TCtx, n: PNode) = # execute new instructions; this redundant opcEof check saves us lots # of allocations in 'execute': if c.code[start].opcode != opcEof: - discard execute(c, start).unpackResult(c.config, nil, wrap = false) + discard execute(c, start).unpackResult(c.config, nilPNode, wrap = false) proc evalExpr*(c: var TCtx, n: PNode): PNode = # deadcode @@ -3630,7 +3634,7 @@ proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstC # TODO: the decrement here is wrong, but the else branch is likely # currently not reached anyway dec(g.config.evalMacroCounter) - c.callsite = nil + c.callsite = nilPNode localReport(c.config, n.info, SemReport( kind: rsemWrongNumberOfGenericParams, countMismatch: ( @@ -3649,5 +3653,5 @@ proc evalMacroCall*(module: PSym; idgen: IdGenerator; g: ModuleGraph; templInstC globalReport(c.config, n.info, reportAst(rsemCyclicTree, n, sym = sym)) dec(g.config.evalMacroCounter) - c.callsite = nil + c.callsite = nilPNode c.mode = oldMode diff --git a/compiler/vm/vmcompilerserdes.nim b/compiler/vm/vmcompilerserdes.nim index 4b19d6bd385..5de3a5e5bd6 100644 --- a/compiler/vm/vmcompilerserdes.nim +++ b/compiler/vm/vmcompilerserdes.nim @@ -51,8 +51,7 @@ template toReport(c: DerefFailureCode): SemReport = # separate parameters would make the function signature unreasonably # large however. -template wrongNode(t: PType): PNode = - mixin info +template wrongNode(t: PType, info: TLineInfo): PNode = newNodeIT(nkEmpty, info, t) proc deserialize(c: TCtx, m: VmMemoryRegion, vt: PVmType, formal, t: PType, info: TLineInfo): PNode @@ -80,7 +79,7 @@ proc deserializeRef*(c: TCtx, slot: HeapSlotHandle, vt: PVmType; f, con: PType, result = c.deserializeObject(src.byteView(), vt.targetType, f, conBase, info) else: result = c.config.newError( - wrongNode(base), + wrongNode(base, info), SemReport(kind: rsemVmUnsupportedNonNil, typ: con)) else: @@ -89,7 +88,7 @@ proc deserializeRef*(c: TCtx, slot: HeapSlotHandle, vt: PVmType; f, con: PType, if e == dfcNil: newNodeIT(nkNilLit, info, f) else: - c.config.newError(wrongNode(f), e.toReport()) + c.config.newError(wrongNode(f, info), e.toReport()) proc deserialize(c: TCtx, m: VmMemoryRegion, vt: PVmType, formal: PType, info: TLineInfo): PNode {.inline.} = deserialize(c, m, vt, formal, formal.skipTypes(SkipSet), info) @@ -151,7 +150,7 @@ proc deserializeObjectPart(c: TCtx, m: VmMemoryRegion, vt: PVmType, ty: PType, info: TLineInfo, - dest: var TNode): tuple[cIdx: int, hasError: bool] = + dest: PNode): tuple[cIdx: int, hasError: bool] = var start = 0 if vt.relFieldStart == 0: discard "nothing to do" @@ -212,7 +211,7 @@ proc deserializeObject(c: TCtx, m: VmMemoryRegion, vt: PVmType; f, con: PType; i result.sons[0] = newNode(nkEmpty) result.sons[0].typ = f - let (len, hasError) = deserializeObjectPart(c, m, vt, con, info, result[]) + let (len, hasError) = deserializeObjectPart(c, m, vt, con, info, result) result.sons.setLen(len) # XXX: this should ideally also shrink the capacity if hasError: @@ -404,8 +403,9 @@ func findInConstr(n: PNode, pos: FieldPosition): PNode = for i in 1.. nkConv(x) result = copyNode(n[0]) result.add m[0] - of nkError: result = nil + of nkError: result = nilPNode else: if n[0].kind in {nkDerefExpr, nkHiddenDeref}: # addr ( deref ( x )) --> x @@ -2178,7 +2178,7 @@ proc genRdVar(c: var TCtx; n: PNode; dest: var TDest; flags: TGenFlags) = # see tests/t99bott for an example that triggers it: cannotEval(c, n) -template needsRegLoad(): untyped = +template needsRegLoad(flags: TGenFlags): untyped = {gfNode, gfNodeAddr} * flags == {} and fitsRegister(n.typ.skipTypes({tyVar, tyLent, tyStatic})) @@ -2195,7 +2195,7 @@ proc genArrAccessOpcode(c: var TCtx; n: PNode; dest: var TDest; opc: TOpcode; c.gABC(n, opc, dest, a, b) elif opc == opcLdStrIdx: c.gABC(n, opc, dest, a, b) - elif needsRegLoad(): + elif needsRegLoad(flags): var cc = c.getTemp(n.typ) c.gABC(n, opc, cc, a, b) c.genRegLoad(n, dest, cc) @@ -2215,7 +2215,7 @@ proc genObjAccess(c: var TCtx; n: PNode; dest: var TDest; flags: TGenFlags) = if dest.isUnset: dest = c.getTemp(n.typ) if {gfNodeAddr} * flags != {}: c.gABC(n, opcLdObjAddr, dest, a, b) - elif needsRegLoad(): + elif needsRegLoad(flags): var cc = c.getTemp(n.typ) c.gABC(n, opcLdObj, cc, a, b) c.genRegLoad(n, dest, cc) @@ -2297,7 +2297,7 @@ proc genCheckedObjAccess(c: var TCtx; n: PNode; dest: var TDest; flags: TGenFlag if {gfNodeAddr} * flags != {}: c.gABC(n, opcLdObjAddr, dest, objR, fieldPos) - elif needsRegLoad(): + elif needsRegLoad(flags): var cc = c.getTemp(accessExpr.typ) c.gABC(n, opcLdObj, cc, objR, fieldPos) c.genRegLoad(n, dest, cc) @@ -2321,7 +2321,7 @@ proc genArrAccess(c: var TCtx; n: PNode; dest: var TDest; flags: TGenFlags) = if dest.isUnset: dest = c.getTemp(n.typ) if gfNodeAddr in flags: c.gABC(n, opcLdObjAddr, dest, a, b) - elif needsRegLoad(): + elif needsRegLoad(flags): let temp = c.getTemp(n.typ) c.gABC(n, opcLdObj, temp, a, b) c.genRegLoad(n, dest, temp) diff --git a/tests/vm/tnimnode.nim b/tests/vm/tnimnode.nim index f1c4d5e5a5f..dba6d008068 100644 --- a/tests/vm/tnimnode.nim +++ b/tests/vm/tnimnode.nim @@ -3,7 +3,6 @@ import macros proc assertEq(arg0,arg1: string): void = if arg0 != arg1: raiseAssert("strings not equal:\n" & arg0 & "\n" & arg1) - # a simple assignment of stmtList to another variable var node {.compileTime.}: NimNode # an assignment of stmtList into an array