diff --git a/compiler/ast.nim b/compiler/ast.nim index e35a0b2031c8..2073a5630862 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -795,6 +795,15 @@ type TPairSeq* = seq[TPair] + TIdPair*[T] = object + key*: ItemId + val*: T + + TIdPairSeq*[T] = seq[TIdPair[T]] + TIdTable*[T] = object + counter*: int + data*: TIdPairSeq[T] + TNodePair* = object h*: Hash # because it is expensive to compute! key*: PNode @@ -939,9 +948,11 @@ proc getPIdent*(a: PNode): PIdent {.inline.} = const moduleShift = when defined(cpu32): 20 else: 24 -template id*(a: PType | PSym): int = +template toId*(a: ItemId): int = let x = a - (x.itemId.module.int shl moduleShift) + x.itemId.item.int + (x.module.int shl moduleShift) + x.item.int + +template id*(a: PType | PSym): int = toId(a.itemId) type IdGenerator* = ref object # unfortunately, we really need the 'shared mutable' aspect here. @@ -1268,6 +1279,11 @@ proc copyStrTable*(dest: var TStrTable, src: TStrTable) = setLen(dest.data, src.data.len) for i in 0..high(src.data): dest.data[i] = src.data[i] +proc copyIdTable*[T](dest: var TIdTable[T], src: TIdTable[T]) = + dest.counter = src.counter + newSeq(dest.data, src.data.len) + for i in 0..high(src.data): dest.data[i] = src.data[i] + proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) = dest.counter = src.counter setLen(dest.data, src.data.len) @@ -1606,6 +1622,16 @@ proc initStrTable*(): TStrTable = result = TStrTable(counter: 0) newSeq(result.data, StartSize) +proc initIdTable*[T](): TIdTable[T] = + result = TIdTable[T](counter: 0) + newSeq(result.data, StartSize) + +proc resetIdTable*[T](x: var TIdTable[T]) = + x.counter = 0 + # clear and set to old initial size: + setLen(x.data, 0) + setLen(x.data, StartSize) + proc initObjectSet*(): TObjectSet = result = TObjectSet(counter: 0) newSeq(result.data, StartSize) @@ -2134,14 +2160,8 @@ proc isTrue*(n: PNode): bool = n.kind == nkIntLit and n.intVal != 0 type - TypeMapping* = Table[ItemId, PType] - SymMapping* = Table[ItemId, PSym] - -template idTableGet*(tab: typed; key: PSym | PType): untyped = tab.getOrDefault(key.itemId) -template idTablePut*(tab: typed; key, val: PSym | PType) = tab[key.itemId] = val - -template initSymMapping*(): Table[ItemId, PSym] = initTable[ItemId, PSym]() -template initTypeMapping*(): Table[ItemId, PType] = initTable[ItemId, PType]() + TypeMapping* = TIdTable[PType] + SymMapping* = TIdTable[PSym] -template resetIdTable*(tab: Table[ItemId, PSym]) = tab.clear() -template resetIdTable*(tab: Table[ItemId, PType]) = tab.clear() +template initSymMapping*(): SymMapping = initIdTable[PSym]() +template initTypeMapping*(): TypeMapping = initIdTable[PType]() diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 7a9892f78ad2..14dc7c59944a 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -713,6 +713,70 @@ iterator items*(tab: TStrTable): PSym = yield s s = nextIter(it, tab) +proc isNil(x: ItemId): bool {.inline.} = + x.module == 0 and x.item == 0 + +proc hasEmptySlot[T](data: TIdPairSeq[T]): bool = + for h in 0..high(data): + if isNil(data[h].key): + return true + result = false + +proc idTableRawGet[T](t: TIdTable[T], key: int): int = + var h: Hash + h = key and high(t.data) # start with real hash value + while not isNil(t.data[h].key): + if toId(t.data[h].key) == key: + return h + h = nextTry(h, high(t.data)) + result = - 1 + +proc getOrDefault*[T](t: TIdTable[T], key: ItemId): T = + var index = idTableRawGet(t, toId(key)) + if index >= 0: result = t.data[index].val + else: result = default(T) + +template idTableGet*[T](t: TIdTable[T], key: PType | PSym): T = + getOrDefault(t, key.itemId) + +proc idTableRawInsert[T](data: var TIdPairSeq[T], key: ItemId, val: T) = + var h: Hash + let keyId = toId(key) + h = keyId and high(data) + while not isNil(data[h].key): + assert(toId(data[h].key) != keyId) + h = nextTry(h, high(data)) + assert(isNil(data[h].key)) + data[h].key = key + data[h].val = val + +proc `[]=`*[T](t: var TIdTable[T], key: ItemId, val: T) = + var + index: int + n: TIdPairSeq[T] + index = idTableRawGet(t, toId(key)) + if index >= 0: + assert(not isNil(t.data[index].key)) + t.data[index].val = val + else: + if mustRehash(t.data.len, t.counter): + newSeq(n, t.data.len * GrowthFactor) + for i in 0..high(t.data): + if not isNil(t.data[i].key): + idTableRawInsert(n, t.data[i].key, t.data[i].val) + assert(hasEmptySlot(n)) + swap(t.data, n) + idTableRawInsert(t.data, key, val) + inc(t.counter) + +template idTablePut*[T](t: var TIdTable[T], key: PType | PSym, val: T) = + t[key.itemId] = val + +iterator idTablePairs*[T](t: TIdTable[T]): tuple[key: ItemId, val: T] = + for i in 0..high(t.data): + if not isNil(t.data[i].key): + yield (t.data[i].key, t.data[i].val) + proc initIITable(x: var TIITable) = x.counter = 0 newSeq(x.data, StartSize) diff --git a/compiler/layeredtable.nim b/compiler/layeredtable.nim index 61a86cff84ee..248ec4bcf2ef 100644 --- a/compiler/layeredtable.nim +++ b/compiler/layeredtable.nim @@ -1,5 +1,5 @@ import std/[tables] -import ast +import ast, astalgo type LayeredIdTableObj* {.acyclic.} = object @@ -28,14 +28,15 @@ proc shallowCopy*(pt: LayeredIdTable): LayeredIdTable {.inline.} = ## copies only the type bindings of the current layer, but not any parent layers, ## useful for write-only bindings result = LayeredIdTable(topLayer: pt.topLayer, nextLayer: pt.nextLayer, previousLen: pt.previousLen) + #copyIdTable(result.topLayer, pt.topLayer) proc currentLen*(pt: LayeredIdTable): int = ## the sum of the cached total binding count of the parents and ## the current binding count, just used to track if bindings were added - pt.previousLen + pt.topLayer.len + pt.previousLen + pt.topLayer.counter proc newTypeMapLayer*(pt: LayeredIdTable): LayeredIdTable = - result = LayeredIdTable(topLayer: initTable[ItemId, PType](), previousLen: pt.currentLen) + result = LayeredIdTable(topLayer: initTypeMapping(), previousLen: pt.currentLen) when useRef: result.nextLayer = pt else: @@ -56,7 +57,7 @@ proc setToPreviousLayer*(pt: var LayeredIdTable) {.inline.} = iterator pairs*(pt: LayeredIdTable): (ItemId, PType) = var tm = pt while true: - for (k, v) in pairs(tm.topLayer): + for (k, v) in idTablePairs(tm.topLayer): yield (k, v) if tm.nextLayer == nil: break diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 90376214db68..eaa723a2c712 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -907,15 +907,15 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, if c.inGenericContext > 0 and c.matchedConcept == nil: result = semGenericStmt(c, n) result.typ() = makeTypeFromExpr(c, result.copyTree) + elif efNoUndeclared in flags: + result = nil elif efExplain notin flags: # repeat the overload resolution, # this time enabling all the diagnostic output (this should fail again) result = semOverloadedCall(c, n, nOrig, filter, flags + {efExplain}) - elif efNoUndeclared notin flags: - result = nil - notFoundError(c, n, errors) else: result = nil + notFoundError(c, n, errors) proc explicitGenericInstError(c: PContext; n: PNode): PNode = localError(c.config, getCallLineInfo(n), errCannotInstantiateX % renderTree(n)) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index fa697f90cd8f..14ca22dcc597 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -17,7 +17,7 @@ when defined(nimPreviewSlimSystem): import options, ast, msgs, idents, renderer, magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable, - types, lowerings, trees, parampatterns + types, lowerings, trees, parampatterns, astalgo import ic / ic @@ -42,7 +42,7 @@ type breakInLoop*: bool # whether we are in a loop without block next*: PProcCon # used for stacking procedure contexts mappingExists*: bool - mapping*: Table[ItemId, PSym] + mapping*: SymMapping caseContext*: seq[tuple[n: PNode, idx: int]] localBindStmts*: seq[PNode] @@ -260,7 +260,7 @@ proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next proc put*(p: PProcCon; key, val: PSym) = if not p.mappingExists: - p.mapping = initTable[ItemId, PSym]() + p.mapping = initSymMapping() p.mappingExists = true #echo "put into table ", key.info p.mapping[key.itemId] = val diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index daee9ba4fc24..a615aeee94a8 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -68,8 +68,8 @@ type TReplTypeVars* = object c*: PContext typeMap*: LayeredIdTable # map PType to PType - symMap*: SymMapping # map PSym to PSym - localCache*: TypeMapping # local cache for remembering already replaced + symMap*: SymMapping # map PSym to PSym + localCache*: TypeMapping # local cache for remembering already replaced # types during instantiation of meta types # (they are not stored in the global cache) info*: TLineInfo diff --git a/compiler/transf.nim b/compiler/transf.nim index 89911daf15bb..a2090af84186 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -40,7 +40,7 @@ import closureiters, lambdalifting type PTransCon = ref object # part of TContext; stackable - mapping: Table[ItemId, PNode] # mapping from symbols to nodes + mapping: TIdTable[PNode] # mapping from symbols to nodes owner: PSym # current owner forStmt: PNode # current for stmt forLoopBody: PNode # transformed for loop body @@ -78,7 +78,7 @@ proc newTransNode(kind: TNodeKind, n: PNode, proc newTransCon(owner: PSym): PTransCon = assert owner != nil - result = PTransCon(mapping: initTable[ItemId, PNode](), owner: owner) + result = PTransCon(mapping: initIdTable[PNode](), owner: owner) proc pushTransCon(c: PTransf, t: PTransCon) = t.next = c.transCon