From 22f56af72be42ef05f26e27f586f4004fb498d94 Mon Sep 17 00:00:00 2001 From: Saem Ghani Date: Thu, 30 Dec 2021 16:31:58 -0800 Subject: [PATCH] first pass of dod ast Breaks/Issues: - no more nil means have to use a sentinel value - lots of effects because of access to `ast_types.state` - tcan_compile_nim, tcompilerapi, and tresults fail - the ic test category takes forever/doesn't come back Next steps: - test fixes - it's pretty slow right now - clean-up type and report storage, tables are super slow signature change for transition procs mean we're creating new node this could well break assumptions that pervade the compiler. Worst case will need to supprot the mutability for now to get the first port, then figure out how to start changing up the compiler based on fork/join/mutation observations. --- compiler/ast/ast.nim | 226 ++++++++++++++++++---- compiler/ast/ast_types.nim | 295 +++++++++++++++++++++++++++-- compiler/ast/astalgo.nim | 4 +- compiler/ast/enumtostr.nim | 2 +- compiler/ast/errorhandling.nim | 13 +- compiler/ast/filters.nim | 2 +- compiler/ast/nimsets.nim | 2 +- compiler/ast/parser.nim | 7 +- compiler/ast/renderer.nim | 7 +- compiler/ast/reports.nim | 8 +- compiler/ast/types.nim | 2 +- compiler/backend/ccgcalls.nim | 2 +- compiler/backend/ccgexprs.nim | 4 +- compiler/backend/ccgstmts.nim | 10 +- compiler/backend/cgmeth.nim | 2 +- compiler/backend/jsgen.nim | 8 +- compiler/front/commands.nim | 26 ++- compiler/front/msgs.nim | 2 +- compiler/front/options.nim | 2 +- compiler/ic/dce.nim | 2 +- compiler/ic/ic.nim | 6 +- compiler/modules/magicsys.nim | 2 +- compiler/modules/modules.nim | 2 +- compiler/sem/closureiters.nim | 8 +- compiler/sem/guards.nim | 12 +- compiler/sem/injectdestructors.nim | 6 +- compiler/sem/lookups.nim | 16 +- compiler/sem/lowerings.nim | 2 +- compiler/sem/nilcheck.nim | 4 +- compiler/sem/passes.nim | 4 +- compiler/sem/patterns.nim | 8 +- compiler/sem/pragmas.nim | 38 ++-- compiler/sem/sem.nim | 4 +- compiler/sem/semcall.nim | 10 +- compiler/sem/semexprs.nim | 39 ++-- compiler/sem/semfold.nim | 24 +-- compiler/sem/semgnrc.nim | 8 +- compiler/sem/semobjconstr.nim | 4 +- compiler/sem/semparallel.nim | 6 +- compiler/sem/sempass2.nim | 8 +- compiler/sem/semstmts.nim | 5 +- compiler/sem/semtypes.nim | 26 ++- compiler/sem/semtypinst.nim | 6 +- compiler/sem/sigmatch.nim | 67 ++++--- compiler/sem/spawn.nim | 20 +- compiler/sem/transf.nim | 10 +- compiler/sem/varpartitions.nim | 2 +- compiler/tools/suggest.nim | 16 +- compiler/utils/astrepr.nim | 14 +- compiler/vm/vm.nim | 36 ++-- compiler/vm/vmcompilerserdes.nim | 16 +- compiler/vm/vmdef.nim | 7 +- compiler/vm/vmgen.nim | 16 +- tests/vm/tnimnode.nim | 1 - 54 files changed, 758 insertions(+), 321 deletions(-) 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