From 4dda5ad2f24befbe003600d221665de27c0fb198 Mon Sep 17 00:00:00 2001 From: metagn Date: Sun, 29 Sep 2024 04:57:04 +0300 Subject: [PATCH] test refactor that uses LayeredIdTable in sigmatch --- compiler/concepts.nim | 12 ++++----- compiler/layeredtable.nim | 32 ++++++++++++++++++++++++ compiler/sem.nim | 6 ++--- compiler/semcall.nim | 4 +-- compiler/semdata.nim | 10 ++++---- compiler/semexprs.nim | 4 +-- compiler/seminst.nim | 12 ++++----- compiler/semstmts.nim | 2 +- compiler/semtypinst.nim | 44 ++++++++++----------------------- compiler/sigmatch.nim | 52 +++++++++++++++++++-------------------- 10 files changed, 96 insertions(+), 82 deletions(-) create mode 100644 compiler/layeredtable.nim diff --git a/compiler/concepts.nim b/compiler/concepts.nim index d48bacdc5257e..800735d3182a1 100644 --- a/compiler/concepts.nim +++ b/compiler/concepts.nim @@ -11,7 +11,7 @@ ## for details. Note this is a first implementation and only the "Concept matching" ## section has been implemented. -import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types +import ast, semdata, lookups, lineinfos, idents, msgs, renderer, types, layeredtable import std/intsets @@ -309,7 +309,7 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool = # error was reported earlier. result = false -proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TypeMapping; invocation: PType): bool = +proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var LayeredIdTable; invocation: PType): bool = ## Entry point from sigmatch. 'concpt' is the concept we try to match (here still a PType but ## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fulfill the ## concept's requirements. If so, we return true and fill the 'bindings' with pairs of @@ -328,16 +328,16 @@ proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TypeMapping; i dest = existingBinding(m, dest) if dest == nil or dest.kind != tyGenericParam: break if dest != nil: - bindings.idTablePut(a, dest) + bindings.put(a, dest) when logBindings: echo "A bind ", a, " ", dest else: - bindings.idTablePut(a, b) + bindings.put(a, b) when logBindings: echo "B bind ", a, " ", b # we have a match, so bind 'arg' itself to 'concpt': - bindings.idTablePut(concpt, arg) + bindings.put(concpt, arg) # invocation != nil means we have a non-atomic concept: if invocation != nil and arg.kind == tyGenericInst and invocation.kidsLen == arg.kidsLen-1: # bind even more generic parameters assert invocation.kind == tyGenericInvocation for i in FirstGenericParamAt ..< invocation.kidsLen: - bindings.idTablePut(invocation[i], arg[i]) + bindings.put(invocation[i], arg[i]) diff --git a/compiler/layeredtable.nim b/compiler/layeredtable.nim new file mode 100644 index 0000000000000..c15d7077d2d1f --- /dev/null +++ b/compiler/layeredtable.nim @@ -0,0 +1,32 @@ +import std/tables +import ast + +type + LayeredIdTable* {.acyclic.} = ref object + topLayer*: TypeMapping + nextLayer*: LayeredIdTable + previousLen*: int # used to track if bindings were added + +proc initLayeredTypeMap*(pt: sink TypeMapping = initTypeMapping()): LayeredIdTable = + result = LayeredIdTable() + result.topLayer = pt + +proc currentLen*(pt: LayeredIdTable): int = + pt.previousLen + pt.topLayer.len + +proc newTypeMapLayer*(pt: LayeredIdTable): LayeredIdTable = + result = LayeredIdTable(nextLayer: pt, topLayer: initTable[ItemId, PType](), previousLen: pt.currentLen) + +proc setToPreviousLayer*(pt: var LayeredIdTable) = + pt = pt.nextLayer + +proc lookup*(typeMap: LayeredIdTable, key: PType): PType = + result = nil + var tm = typeMap + while tm != nil: + result = getOrDefault(tm.topLayer, key.itemId) + if result != nil: return + tm = tm.nextLayer + +proc put*(typeMap: LayeredIdTable, key, value: PType) {.inline.} = + typeMap.topLayer[key.itemId] = value diff --git a/compiler/sem.nim b/compiler/sem.nim index 72d8dc5b040a2..d8a9e50043d6e 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -18,7 +18,7 @@ import evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, lowerings, plugins/active, lineinfos, int128, isolation_check, typeallowed, modulegraphs, enumtostr, concepts, astmsgs, - extccomp + extccomp, layeredtable import vtables import std/[strtabs, math, tables, intsets, strutils, packedsets] @@ -473,7 +473,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, # e.g. template foo(T: typedesc): seq[T] # We will instantiate the return type here, because # we now know the supplied arguments - var paramTypes = initTypeMapping() + var paramTypes = initLayeredTypeMap() for param, value in genericParamsInMacroCall(s, call): var givenType = value.typ # the sym nodes used for the supplied generic arguments for @@ -481,7 +481,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode, # in this case, get the type directly from the sym if givenType == nil and value.kind == nkSym and value.sym.typ != nil: givenType = value.sym.typ - idTablePut(paramTypes, param.typ, givenType) + put(paramTypes, param.typ, givenType) retType = generateTypeInstance(c, paramTypes, macroResult.info, retType) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 13f2273a9b9d1..02c6529ae7c8b 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -748,7 +748,7 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = if t[i] == nil or u[i] == nil: return stackPut(t[i], u[i]) of tyGenericParam: - let prebound = x.bindings.idTableGet(t) + let prebound = x.bindings.lookup(t) if prebound != nil: continue # Skip param, already bound @@ -760,7 +760,7 @@ proc inheritBindings(c: PContext, x: var TCandidate, expectedType: PType) = discard # update bindings for i in 0 ..< flatUnbound.len(): - x.bindings.idTablePut(flatUnbound[i], flatBound[i]) + x.bindings.put(flatUnbound[i], flatBound[i]) proc semResolvedCall(c: PContext, x: var TCandidate, n: PNode, flags: TExprFlags; diff --git a/compiler/semdata.nim b/compiler/semdata.nim index ca35ddc53a6e4..16d3d6f5b85b1 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -15,8 +15,8 @@ when defined(nimPreviewSlimSystem): import std/assertions import - options, ast, astalgo, msgs, idents, renderer, - magicsys, vmdef, modulegraphs, lineinfos, pathutils + options, ast, msgs, idents, renderer, + magicsys, vmdef, modulegraphs, lineinfos, pathutils, layeredtable import ic / ic @@ -136,10 +136,10 @@ type semOverloadedCall*: proc (c: PContext, n, nOrig: PNode, filter: TSymKinds, flags: TExprFlags, expectedType: PType = nil): PNode {.nimcall.} semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.} - semInferredLambda*: proc(c: PContext, pt: Table[ItemId, PType], n: PNode): PNode - semGenerateInstance*: proc (c: PContext, fn: PSym, pt: Table[ItemId, PType], + semInferredLambda*: proc(c: PContext, pt: LayeredIdTable, n: PNode): PNode + semGenerateInstance*: proc (c: PContext, fn: PSym, pt: LayeredIdTable, info: TLineInfo): PSym - instantiateOnlyProcType*: proc (c: PContext, pt: TypeMapping, + instantiateOnlyProcType*: proc (c: PContext, pt: LayeredIdTable, prc: PSym, info: TLineInfo): PType # used by sigmatch for explicit generic instantiations includedFiles*: IntSet # used to detect recursive include files diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 6a3b401111e09..7e800ea45e5f5 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2516,8 +2516,8 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType; let sym = magicsys.getCompilerProc(c.graph, "nimCreateFlowVar") if sym == nil: localError(c.config, info, "system needs: nimCreateFlowVar") - var bindings = initTypeMapping() - bindings.idTablePut(sym.ast[genericParamsPos][0].typ, t) + var bindings = initLayeredTypeMap() + bindings.put(sym.ast[genericParamsPos][0].typ, t) result = c.semGenerateInstance(c, sym, bindings, info) # since it's an instantiation, we unmark it as a compilerproc. Otherwise # codegen would fail: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 1bc6d31a2a8a3..ada47feb9e61e 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -34,7 +34,7 @@ proc pushProcCon*(c: PContext; owner: PSym) = const errCannotInstantiateX = "cannot instantiate: '$1'" -iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PSym = +iterator instantiateGenericParamList(c: PContext, n: PNode, pt: LayeredIdTable): PSym = internalAssert c.config, n.kind == nkGenericParams for a in n.items: internalAssert c.config, a.kind == nkSym @@ -43,7 +43,7 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PS let symKind = if q.typ.kind == tyStatic: skConst else: skType var s = newSym(symKind, q.name, c.idgen, getCurrOwner(c), q.info) s.flags.incl {sfUsed, sfFromGeneric} - var t = idTableGet(pt, q.typ) + var t = lookup(pt, q.typ) if t == nil: if tfRetType in q.typ.flags: # keep the generic type and allow the return type to be bound @@ -220,7 +220,7 @@ proc referencesAnotherParam(n: PNode, p: PSym): bool = if referencesAnotherParam(n[i], p): return true return false -proc instantiateProcType(c: PContext, pt: TypeMapping, +proc instantiateProcType(c: PContext, pt: LayeredIdTable, prc: PSym, info: TLineInfo) = # XXX: Instantiates a generic proc signature, while at the same # time adding the instantiated proc params into the current scope. @@ -237,7 +237,7 @@ proc instantiateProcType(c: PContext, pt: TypeMapping, # will need to use openScope, addDecl, etc. #addDecl(c, prc) pushInfoContext(c.config, info) - var typeMap = initLayeredTypeMap(pt) + var typeMap = newTypeMapLayer(pt) var cl = initTypeVars(c, typeMap, info, nil) var result = instCopyType(cl, prc.typ) let originalParams = result.n @@ -324,7 +324,7 @@ proc instantiateProcType(c: PContext, pt: TypeMapping, prc.typ = result popInfoContext(c.config) -proc instantiateOnlyProcType(c: PContext, pt: TypeMapping, prc: PSym, info: TLineInfo): PType = +proc instantiateOnlyProcType(c: PContext, pt: LayeredIdTable, prc: PSym, info: TLineInfo): PType = # instantiates only the type of a given proc symbol # used by sigmatch for explicit generics # wouldn't be needed if sigmatch could handle complex cases, @@ -360,7 +360,7 @@ proc getLocalPassC(c: PContext, s: PSym): string = for p in n: extractPassc(p) -proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping, +proc generateInstance(c: PContext, fn: PSym, pt: LayeredIdTable, info: TLineInfo): PSym = ## Generates a new instance of a generic procedure. ## The `pt` parameter is a type-unsafe mapping table used to link generic diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f5f8fea0c6088..3dad09edfd48a 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1969,7 +1969,7 @@ proc semProcAnnotation(c: PContext, prc: PNode; return result -proc semInferredLambda(c: PContext, pt: TypeMapping, n: PNode): PNode = +proc semInferredLambda(c: PContext, pt: LayeredIdTable, n: PNode): PNode = ## used for resolving 'auto' in lambdas based on their callsite var n = n let original = n[namePos].sym diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 759e8e6ab0720..c32c69af3f1ec 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -12,7 +12,7 @@ import std / tables import ast, astalgo, msgs, types, magicsys, semdata, renderer, options, - lineinfos, modulegraphs + lineinfos, modulegraphs, layeredtable when defined(nimPreviewSlimSystem): import std/assertions @@ -65,10 +65,6 @@ proc cacheTypeInst(c: PContext; inst: PType) = addToGenericCache(c, gt.sym, inst) type - LayeredIdTable* {.acyclic.} = ref object - topLayer*: TypeMapping - nextLayer*: LayeredIdTable - TReplTypeVars* = object c*: PContext typeMap*: LayeredIdTable # map PType to PType @@ -88,23 +84,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode -proc initLayeredTypeMap*(pt: sink TypeMapping): LayeredIdTable = - result = LayeredIdTable() - result.topLayer = pt - proc newTypeMapLayer*(cl: var TReplTypeVars): LayeredIdTable = - result = LayeredIdTable(nextLayer: cl.typeMap, topLayer: initTable[ItemId, PType]()) - -proc lookup(typeMap: LayeredIdTable, key: PType): PType = - result = nil - var tm = typeMap - while tm != nil: - result = getOrDefault(tm.topLayer, key.itemId) - if result != nil: return - tm = tm.nextLayer - -template put(typeMap: LayeredIdTable, key, value: PType) = - typeMap.topLayer[key.itemId] = value + result = newTypeMapLayer(cl.typeMap) template checkMetaInvariants(cl: TReplTypeVars, t: PType) = # noop code when false: @@ -500,7 +481,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags) result.flags = result.flags + newbody.flags - tfInstClearedFlags - cl.typeMap = cl.typeMap.nextLayer + setToPreviousLayer(cl.typeMap) # This is actually wrong: tgeneric_closure fails with this line: #newbody.callConv = body.callConv @@ -791,19 +772,20 @@ proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo; localCache: initTypeMapping(), typeMap: typeMap, info: info, c: p, owner: owner) -proc replaceTypesInBody*(p: PContext, pt: TypeMapping, n: PNode; +proc replaceTypesInBody*(p: PContext, pt: LayeredIdTable, n: PNode; owner: PSym, allowMetaTypes = false, fromStaticExpr = false, expectedType: PType = nil): PNode = - var typeMap = initLayeredTypeMap(pt) + var typeMap = newTypeMapLayer(pt) var cl = initTypeVars(p, typeMap, n.info, owner) cl.allowMetaTypes = allowMetaTypes pushInfoContext(p.config, n.info) result = replaceTypeVarsN(cl, n, expectedType = expectedType) popInfoContext(p.config) -proc prepareTypesInBody*(p: PContext, pt: TypeMapping, n: PNode; +proc prepareTypesInBody*(p: PContext, pt: LayeredIdTable, n: PNode; owner: PSym = nil): PNode = - var typeMap = initLayeredTypeMap(pt) + var typeMap = newTypeMapLayer(pt) + defer: var cl = initTypeVars(p, typeMap, n.info, owner) pushInfoContext(p.config, n.info) result = prepareNode(cl, n) @@ -836,13 +818,13 @@ proc recomputeFieldPositions*(t: PType; obj: PNode; currPosition: var int) = inc currPosition else: discard "cannot happen" -proc generateTypeInstance*(p: PContext, pt: TypeMapping, info: TLineInfo, +proc generateTypeInstance*(p: PContext, pt: LayeredIdTable, info: TLineInfo, t: PType): PType = # Given `t` like Foo[T] # pt: Table with type mappings: T -> int # Desired result: Foo[int] # proc (x: T = 0); T -> int ----> proc (x: int = 0) - var typeMap = initLayeredTypeMap(pt) + var typeMap = newTypeMapLayer(pt) var cl = initTypeVars(p, typeMap, info, nil) pushInfoContext(p.config, info) result = replaceTypeVarsT(cl, t) @@ -852,15 +834,15 @@ proc generateTypeInstance*(p: PContext, pt: TypeMapping, info: TLineInfo, var position = 0 recomputeFieldPositions(objType, objType.n, position) -proc prepareMetatypeForSigmatch*(p: PContext, pt: TypeMapping, info: TLineInfo, +proc prepareMetatypeForSigmatch*(p: PContext, pt: LayeredIdTable, info: TLineInfo, t: PType): PType = - var typeMap = initLayeredTypeMap(pt) + var typeMap = newTypeMapLayer(pt) var cl = initTypeVars(p, typeMap, info, nil) cl.allowMetaTypes = true pushInfoContext(p.config, info) result = replaceTypeVarsT(cl, t) popInfoContext(p.config) -template generateTypeInstance*(p: PContext, pt: TypeMapping, arg: PNode, +template generateTypeInstance*(p: PContext, pt: LayeredIdTable, arg: PNode, t: PType): untyped = generateTypeInstance(p, pt, arg.info, t) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index f09fd6b69fe95..d09246fcd18cb 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -13,7 +13,7 @@ import ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, magicsys, idents, lexer, options, parampatterns, trees, - linter, lineinfos, lowerings, modulegraphs, concepts + linter, lineinfos, lowerings, modulegraphs, concepts, layeredtable import std/[intsets, strutils, tables] @@ -56,7 +56,7 @@ type calleeScope*: int # scope depth: # is this a top-level symbol or a nested proc? call*: PNode # modified call - bindings*: TypeMapping # maps types to types + bindings*: LayeredIdTable # maps types to types magic*: TMagic # magic of operation baseTypeMatch: bool # needed for conversions from T to openarray[T] # for example @@ -114,21 +114,21 @@ proc initCandidateAux(ctx: PContext, proc initCandidate*(ctx: PContext, callee: PType): TCandidate = result = initCandidateAux(ctx, callee) result.calleeSym = nil - result.bindings = initTypeMapping() + result.bindings = initLayeredTypeMap() 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 = idTableGet(c.bindings, key) + let old = lookup(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)) + put(c.bindings, key, val.skipIntLit(c.c.idgen)) proc typeRel*(c: var TCandidate, f, aOrig: PType, flags: TTypeRelFlags = {}): TTypeRelation @@ -138,7 +138,7 @@ proc matchGenericParam(m: var TCandidate, formal: PType, n: PNode) = if m.c.inGenericContext > 0: # don't match yet-unresolved generic instantiations while arg != nil and arg.kind == tyGenericParam: - arg = idTableGet(m.bindings, arg) + arg = lookup(m.bindings, arg) if arg == nil or arg.containsUnresolvedType: m.state = csNoMatch return @@ -218,7 +218,7 @@ proc copyingEraseVoidParams(m: TCandidate, t: var PType) = var f = original[i] var isVoidParam = f.kind == tyVoid if not isVoidParam: - let prev = idTableGet(m.bindings, f) + let prev = lookup(m.bindings, f) if prev != nil: f = prev isVoidParam = f.kind == tyVoid if isVoidParam: @@ -246,7 +246,7 @@ proc initCandidate*(ctx: PContext, callee: PSym, result.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil result.diagnosticsEnabled = diagnosticsEnabled result.magic = result.calleeSym.magic - result.bindings = initTypeMapping() + result.bindings = initLayeredTypeMap() if binding != nil and callee.kind in routineKinds: matchGenericParams(result, binding, callee) let genericMatch = result.state @@ -487,7 +487,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType = result = t if c.isNoCall: return while true: - result = idTableGet(c.bindings, t) + result = lookup(c.bindings, t) if result == nil: break # it's ok, no match # example code that triggers it: @@ -632,7 +632,7 @@ proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) = if fGenericOrigin != nil and last.kind == tyGenericInst and last.kidsLen-1 == fGenericOrigin.kidsLen: for i in FirstGenericParamAt.. isGeneric: result = isGeneric of tyStatic: - let prev = idTableGet(c.bindings, f) + let prev = lookup(c.bindings, f) if prev == nil: if aOrig.kind == tyStatic: if c.c.inGenericContext > 0 and aOrig.n == nil and not c.isNoCall: @@ -2060,7 +2060,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, c.inferredTypes.add f f.add a of tyTypeDesc: - var prev = idTableGet(c.bindings, f) + var prev = lookup(c.bindings, f) if prev == nil: # proc foo(T: typedesc, x: T) # when `f` is an unresolved typedesc, `a` could be any @@ -2151,7 +2151,7 @@ proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation = proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate, f: PType): PType = - result = idTableGet(m.bindings, f) + result = lookup(m.bindings, f) if result == nil: result = generateTypeInstance(c, m.bindings, arg, f) if result == nil: @@ -2371,9 +2371,9 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType, var instantiationCounter = 0 var lastBindingCount = -1 while r in {isBothMetaConvertible, isInferred, isInferredConvertible} and - lastBindingCount != m.bindings.len and + lastBindingCount != m.bindings.currentLen and instantiationCounter < 100: - lastBindingCount = m.bindings.len + lastBindingCount = m.bindings.currentLen inc(instantiationCounter) if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds: result = c.semInferredLambda(c, m.bindings, arg) @@ -2960,7 +2960,7 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) = # proc foo(x: T = 0.0) # foo() if {tfImplicitTypeParam, tfGenericTypeParam} * formal.typ.flags != {}: - let existing = idTableGet(m.bindings, formal.typ) + let existing = lookup(m.bindings, formal.typ) if existing == nil or existing.kind == tyTypeDesc: # see bug #11600: put(m, formal.typ, defaultValue.typ)