bugfix: proper cache for generic instantiations
This commit is contained in:
parent
81a917390b
commit
569c1ce5ec
24 changed files with 459 additions and 643 deletions
|
|
@ -15,7 +15,7 @@ import
|
|||
options, intsets,
|
||||
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
|
||||
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth,
|
||||
rodutils
|
||||
rodutils, renderer
|
||||
|
||||
when options.hasTinyCBackend:
|
||||
import tccgen
|
||||
|
|
|
|||
|
|
@ -134,15 +134,13 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
|||
include semtypes, semexprs, semgnrc, semstmts
|
||||
|
||||
proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||
for i in countup(c.lastGenericIdx, sonsLen(c.generics) - 1):
|
||||
var it = c.generics.sons[i].sons[1]
|
||||
if it.kind != nkSym: InternalError("addCodeForGenerics")
|
||||
var prc = it.sym
|
||||
for i in countup(lastGenericIdx, Len(generics) - 1):
|
||||
var prc = generics[i].instSym
|
||||
if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone:
|
||||
if prc.ast == nil or prc.ast.sons[codePos] == nil:
|
||||
InternalError(prc.info, "no code for " & prc.name.s)
|
||||
addSon(n, prc.ast)
|
||||
c.lastGenericIdx = sonsLen(c.generics)
|
||||
lastGenericIdx = Len(generics)
|
||||
|
||||
proc semExprNoFlags(c: PContext, n: PNode): PNode =
|
||||
result = semExpr(c, n, {})
|
||||
|
|
@ -174,7 +172,7 @@ proc myOpenCached(module: PSym, filename: string,
|
|||
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
result = semStmt(c, n)
|
||||
# BUGFIX: process newly generated generics here, not at the end!
|
||||
if sonsLen(c.generics) > 0:
|
||||
if lastGenericIdx < Len(generics):
|
||||
var a = newNodeI(nkStmtList, n.info)
|
||||
addCodeForGenerics(c, a)
|
||||
if sonsLen(a) > 0:
|
||||
|
|
|
|||
|
|
@ -119,12 +119,4 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
|||
# candidateCount != 1: return explicitGenericInstError(n)
|
||||
else:
|
||||
assert false
|
||||
|
||||
when false:
|
||||
var x: TCandidate
|
||||
initCandidate(x, s, n)
|
||||
var newInst = generateInstance(c, s, x.bindings, n.info)
|
||||
|
||||
markUsed(n, s)
|
||||
result = newSymNode(newInst, n.info)
|
||||
|
||||
|
|
|
|||
|
|
@ -33,16 +33,17 @@ type
|
|||
nestedBlockCounter*: int # whether we are in a block or not
|
||||
next*: PProcCon # used for stacking procedure contexts
|
||||
|
||||
TInstantiatedSymbol* {.final.} = object
|
||||
genericSym*, instSym*: PSym
|
||||
concreteTypes*: seq[PType]
|
||||
|
||||
PContext* = ref TContext
|
||||
TContext* = object of TPassContext # a context represents a module
|
||||
module*: PSym # the module sym belonging to the context
|
||||
p*: PProcCon # procedure context
|
||||
InstCounter*: int # to prevent endless instantiations
|
||||
generics*: PNode # a list of the things to compile; list of
|
||||
# nkExprEqExpr nodes which contain the
|
||||
# generic symbol and the instantiated symbol
|
||||
|
||||
threadEntries*: TSymSeq # list of thread entries to check
|
||||
lastGenericIdx*: int # used for the generics stack
|
||||
tab*: TSymTab # each module has its own symbol table
|
||||
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
|
||||
# store this info in the syms themselves!)
|
||||
|
|
@ -58,6 +59,8 @@ type
|
|||
|
||||
|
||||
var gInstTypes*: TIdTable # map PType to PType
|
||||
var generics*: seq[TInstantiatedSymbol] = @[] # a list of the things to compile
|
||||
var lastGenericIdx*: int # used for the generics stack
|
||||
|
||||
proc newContext*(module: PSym, nimfile: string): PContext
|
||||
|
||||
|
|
@ -124,7 +127,6 @@ proc newContext(module: PSym, nimfile: string): PContext =
|
|||
initLinkedList(result.libs)
|
||||
append(result.optionStack, newOptionEntry())
|
||||
result.module = module
|
||||
result.generics = newNode(nkStmtList)
|
||||
result.threadEntries = @[]
|
||||
result.converters = @[]
|
||||
result.filename = nimfile
|
||||
|
|
|
|||
|
|
@ -9,15 +9,17 @@
|
|||
|
||||
# This module implements the instantiation of generic procs.
|
||||
|
||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
|
||||
if (n.kind != nkGenericParams):
|
||||
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
entry: var TInstantiatedSymbol) =
|
||||
if n.kind != nkGenericParams:
|
||||
InternalError(n.info, "instantiateGenericParamList; no generic params")
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
newSeq(entry.concreteTypes, n.len)
|
||||
for i in countup(0, n.len - 1):
|
||||
var a = n.sons[i]
|
||||
if a.kind != nkSym:
|
||||
InternalError(a.info, "instantiateGenericParamList; no symbol")
|
||||
var q = a.sym
|
||||
if not (q.typ.kind in {tyTypeDesc, tyGenericParam}): continue
|
||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam}: continue
|
||||
var s = newSym(skType, q.name, getCurrOwner())
|
||||
s.info = q.info
|
||||
incl(s.flags, sfUsed)
|
||||
|
|
@ -29,24 +31,23 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
|
|||
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
||||
s.typ = t
|
||||
addDecl(c, s)
|
||||
entry.concreteTypes[i] = t
|
||||
|
||||
proc GenericCacheGet(c: PContext, genericSym, instSym: PSym): PSym =
|
||||
result = nil
|
||||
for i in countup(0, sonsLen(c.generics) - 1):
|
||||
if c.generics.sons[i].kind != nkExprEqExpr:
|
||||
InternalError(genericSym.info, "GenericCacheGet")
|
||||
var a = c.generics.sons[i].sons[0].sym
|
||||
if genericSym.id == a.id:
|
||||
var b = c.generics.sons[i].sons[1].sym
|
||||
if equalParams(b.typ.n, instSym.typ.n) == paramsEqual:
|
||||
#echo "found in cache: ", getProcHeader(instSym)
|
||||
return b
|
||||
proc sameInstantiation(a, b: TInstantiatedSymbol): bool =
|
||||
if a.genericSym.id == b.genericSym.id and
|
||||
a.concreteTypes.len == b.concreteTypes.len:
|
||||
for i in 0 .. < a.concreteTypes.len:
|
||||
if not sameType(a.concreteTypes[i], b.concreteTypes[i]): return
|
||||
result = true
|
||||
|
||||
proc GenericCacheAdd(c: PContext, genericSym, instSym: PSym) =
|
||||
var n = newNode(nkExprEqExpr)
|
||||
addSon(n, newSymNode(genericSym))
|
||||
addSon(n, newSymNode(instSym))
|
||||
addSon(c.generics, n)
|
||||
proc GenericCacheGet(c: PContext, entry: var TInstantiatedSymbol): PSym =
|
||||
for i in countup(0, Len(generics) - 1):
|
||||
if sameInstantiation(entry, generics[i]):
|
||||
result = generics[i].instSym
|
||||
# checking for the concrete parameter list is wrong and unnecessary!
|
||||
#if equalParams(b.typ.n, instSym.typ.n) == paramsEqual:
|
||||
#echo "found in cache: ", getProcHeader(result)
|
||||
return
|
||||
|
||||
proc removeDefaultParamValues(n: PNode) =
|
||||
# we remove default params, because they cannot be instantiated properly
|
||||
|
|
@ -81,11 +82,14 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
result.ast = n
|
||||
pushOwner(result)
|
||||
openScope(c.tab)
|
||||
if (n.sons[genericParamsPos].kind == nkEmpty):
|
||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
InternalError(n.info, "generateInstance")
|
||||
n.sons[namePos] = newSymNode(result)
|
||||
pushInfoContext(info)
|
||||
instantiateGenericParamList(c, n.sons[genericParamsPos], pt)
|
||||
var entry: TInstantiatedSymbol
|
||||
entry.instSym = result
|
||||
entry.genericSym = fn
|
||||
instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry)
|
||||
n.sons[genericParamsPos] = ast.emptyNode
|
||||
# semantic checking for the parameters:
|
||||
if n.sons[paramsPos].kind != nkEmpty:
|
||||
|
|
@ -96,10 +100,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|||
result.typ = newTypeS(tyProc, c)
|
||||
addSon(result.typ, nil)
|
||||
result.typ.callConv = fn.typ.callConv
|
||||
var oldPrc = GenericCacheGet(c, fn, result)
|
||||
if oldPrc == nil:
|
||||
var oldPrc = GenericCacheGet(c, entry)
|
||||
if oldPrc == nil:
|
||||
# add it here, so that recursive generic procs are possible:
|
||||
GenericCacheAdd(c, fn, result)
|
||||
generics.add(entry)
|
||||
addDecl(c, result)
|
||||
if n.sons[codePos].kind != nkEmpty:
|
||||
pushProcCon(c, result)
|
||||
|
|
|
|||
|
|
@ -358,6 +358,8 @@ proc analyse(c: PProcCtx, n: PNode): TThreadOwner =
|
|||
of nkAsmStmt, nkPragma, nkIteratorDef, nkProcDef, nkMethodDef,
|
||||
nkConverterDef, nkMacroDef, nkTemplateDef:
|
||||
result = toVoid
|
||||
of nkExprColonExpr:
|
||||
result = analyse(c, n.sons[1])
|
||||
else: InternalError(n.info, "analysis not implemented for: " & $n.kind)
|
||||
|
||||
proc analyseThreadProc*(prc: PSym) =
|
||||
|
|
@ -368,17 +370,6 @@ proc analyseThreadProc*(prc: PSym) =
|
|||
c.mapping[formal.id] = toTheirs # thread receives foreign data!
|
||||
discard analyse(c, prc.ast.sons[codePos])
|
||||
|
||||
when false:
|
||||
proc analyseThreadCreationCall(n: PNode) =
|
||||
# thread proc is second param of ``createThread``:
|
||||
if n[2].kind != nkSym or n[2].sym.kind != skProc:
|
||||
Message(n.info, warnAnalysisLoophole, renderTree(n))
|
||||
return
|
||||
analyseProc(n[2].sym)
|
||||
|
||||
proc AnalyseThread*(threadCreation: PNode) =
|
||||
analyseThreadCreationCall(threadCreation)
|
||||
|
||||
proc needsGlobalAnalysis*: bool =
|
||||
result = gGlobalOptions * {optThreads, optThreadAnalysis} ==
|
||||
{optThreads, optThreadAnalysis}
|
||||
|
|
|
|||
|
|
@ -12,19 +12,6 @@
|
|||
import
|
||||
ast, astalgo, lexer, msgs, strutils, wordrecg
|
||||
|
||||
proc getMagic*(op: PNode): TMagic
|
||||
|
||||
proc isConstExpr*(n: PNode): bool
|
||||
proc flattenTree*(root: PNode, op: TMagic): PNode
|
||||
proc TreeToSym*(t: PNode): PSym
|
||||
proc SwapOperands*(op: PNode)
|
||||
proc getOpSym*(op: PNode): PSym
|
||||
proc getProcSym*(call: PNode): PSym
|
||||
proc ExprStructuralEquivalent*(a, b: PNode): bool
|
||||
proc sameTree*(a, b: PNode): bool
|
||||
proc cyclicTree*(n: PNode): bool
|
||||
# implementation
|
||||
|
||||
proc hasSon(father, son: PNode): bool =
|
||||
for i in countup(0, sonsLen(father) - 1):
|
||||
if father.sons[i] == son:
|
||||
|
|
@ -45,11 +32,11 @@ proc cyclicTreeAux(n, s: PNode): bool =
|
|||
result = false
|
||||
delSon(s, m)
|
||||
|
||||
proc cyclicTree(n: PNode): bool =
|
||||
proc cyclicTree*(n: PNode): bool =
|
||||
var s = newNodeI(nkEmpty, n.info)
|
||||
result = cyclicTreeAux(n, s)
|
||||
|
||||
proc ExprStructuralEquivalent(a, b: PNode): bool =
|
||||
proc ExprStructuralEquivalent*(a, b: PNode): bool =
|
||||
result = false
|
||||
if a == b:
|
||||
result = true
|
||||
|
|
@ -69,7 +56,7 @@ proc ExprStructuralEquivalent(a, b: PNode): bool =
|
|||
if not ExprStructuralEquivalent(a.sons[i], b.sons[i]): return
|
||||
result = true
|
||||
|
||||
proc sameTree(a, b: PNode): bool =
|
||||
proc sameTree*(a, b: PNode): bool =
|
||||
result = false
|
||||
if a == b:
|
||||
result = true
|
||||
|
|
@ -93,10 +80,10 @@ proc sameTree(a, b: PNode): bool =
|
|||
if not sameTree(a.sons[i], b.sons[i]): return
|
||||
result = true
|
||||
|
||||
proc getProcSym(call: PNode): PSym =
|
||||
proc getProcSym*(call: PNode): PSym =
|
||||
result = call.sons[0].sym
|
||||
|
||||
proc getOpSym(op: PNode): PSym =
|
||||
proc getOpSym*(op: PNode): PSym =
|
||||
if not (op.kind in {nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit}):
|
||||
result = nil
|
||||
else:
|
||||
|
|
@ -104,7 +91,7 @@ proc getOpSym(op: PNode): PSym =
|
|||
if op.sons[0].Kind == nkSym: result = op.sons[0].sym
|
||||
else: result = nil
|
||||
|
||||
proc getMagic(op: PNode): TMagic =
|
||||
proc getMagic*(op: PNode): TMagic =
|
||||
case op.kind
|
||||
of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit, nkPrefix, nkPostfix,
|
||||
nkInfix:
|
||||
|
|
@ -113,10 +100,10 @@ proc getMagic(op: PNode): TMagic =
|
|||
else: result = mNone
|
||||
else: result = mNone
|
||||
|
||||
proc TreeToSym(t: PNode): PSym =
|
||||
proc TreeToSym*(t: PNode): PSym =
|
||||
result = t.sym
|
||||
|
||||
proc isConstExpr(n: PNode): bool =
|
||||
proc isConstExpr*(n: PNode): bool =
|
||||
result = (n.kind in
|
||||
{nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
|
||||
nkFloatLit..nkFloat64Lit, nkNilLit}) or (nfAllConst in n.flags)
|
||||
|
|
@ -128,14 +115,14 @@ proc flattenTreeAux(d, a: PNode, op: TMagic) =
|
|||
else:
|
||||
addSon(d, copyTree(a))
|
||||
|
||||
proc flattenTree(root: PNode, op: TMagic): PNode =
|
||||
proc flattenTree*(root: PNode, op: TMagic): PNode =
|
||||
result = copyNode(root)
|
||||
if (getMagic(root) == op):
|
||||
# BUGFIX: forget to copy prc
|
||||
addSon(result, copyNode(root.sons[0]))
|
||||
flattenTreeAux(result, root, op)
|
||||
|
||||
proc SwapOperands(op: PNode) =
|
||||
proc SwapOperands*(op: PNode) =
|
||||
var tmp = op.sons[1]
|
||||
op.sons[1] = op.sons[2]
|
||||
op.sons[2] = tmp
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue