130 lines
4.6 KiB
Nim
Executable file
130 lines
4.6 KiB
Nim
Executable file
#
|
|
#
|
|
# The Nimrod Compiler
|
|
# (c) Copyright 2011 Andreas Rumpf
|
|
#
|
|
# See the file "copying.txt", included in this
|
|
# distribution, for details about the copyright.
|
|
#
|
|
|
|
# This module implements the instantiation of generic procs.
|
|
|
|
proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable) =
|
|
if (n.kind != nkGenericParams):
|
|
InternalError(n.info, "instantiateGenericParamList; no generic params")
|
|
for i in countup(0, sonsLen(n) - 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
|
|
var s = newSym(skType, q.name, getCurrOwner())
|
|
s.info = q.info
|
|
incl(s.flags, sfUsed)
|
|
var t = PType(IdTableGet(pt, q.typ))
|
|
if t == nil:
|
|
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
|
break
|
|
if t.kind == tyGenericParam:
|
|
InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
|
|
s.typ = t
|
|
addDecl(c, s)
|
|
|
|
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 GenericCacheAdd(c: PContext, genericSym, instSym: PSym) =
|
|
var n = newNode(nkExprEqExpr)
|
|
addSon(n, newSymNode(genericSym))
|
|
addSon(n, newSymNode(instSym))
|
|
addSon(c.generics, n)
|
|
|
|
proc removeDefaultParamValues(n: PNode) =
|
|
# we remove default params, because they cannot be instantiated properly
|
|
# and they are not needed anyway for instantiation (each param is already
|
|
# provided).
|
|
when false:
|
|
for i in countup(1, sonsLen(n)-1):
|
|
var a = n.sons[i]
|
|
if a.kind != nkIdentDefs: IllFormedAst(a)
|
|
var L = a.len
|
|
if a.sons[L-1].kind != nkEmpty and a.sons[L-2].kind != nkEmpty:
|
|
# ``param: typ = defaultVal``.
|
|
# We don't need defaultVal for semantic checking and it's wrong for
|
|
# ``cmp: proc (a, b: T): int = cmp``. Hm, for ``cmp = cmp`` that is
|
|
# not possible... XXX We don't solve this issue here.
|
|
a.sons[L-1] = ast.emptyNode
|
|
|
|
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
|
info: TLineInfo): PSym =
|
|
# generates an instantiated proc
|
|
if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
|
|
inc(c.InstCounter)
|
|
# NOTE: for access of private fields within generics from a different module
|
|
# and other identifiers we fake the current module temporarily!
|
|
# XXX bad hack!
|
|
var oldMod = c.module
|
|
c.module = getModule(fn)
|
|
result = copySym(fn, false)
|
|
incl(result.flags, sfFromGeneric)
|
|
result.owner = getCurrOwner().owner
|
|
var n = copyTree(fn.ast)
|
|
result.ast = n
|
|
pushOwner(result)
|
|
openScope(c.tab)
|
|
if (n.sons[genericParamsPos].kind == nkEmpty):
|
|
InternalError(n.info, "generateInstance")
|
|
n.sons[namePos] = newSymNode(result)
|
|
pushInfoContext(info)
|
|
instantiateGenericParamList(c, n.sons[genericParamsPos], pt)
|
|
n.sons[genericParamsPos] = ast.emptyNode
|
|
# semantic checking for the parameters:
|
|
if n.sons[paramsPos].kind != nkEmpty:
|
|
removeDefaultParamValues(n.sons[ParamsPos])
|
|
semParamList(c, n.sons[ParamsPos], nil, result)
|
|
addParams(c, result.typ.n)
|
|
else:
|
|
result.typ = newTypeS(tyProc, c)
|
|
addSon(result.typ, nil)
|
|
result.typ.callConv = fn.typ.callConv
|
|
var oldPrc = GenericCacheGet(c, fn, result)
|
|
if oldPrc == nil:
|
|
# add it here, so that recursive generic procs are possible:
|
|
GenericCacheAdd(c, fn, result)
|
|
addDecl(c, result)
|
|
if n.sons[codePos].kind != nkEmpty:
|
|
pushProcCon(c, result)
|
|
if result.kind in {skProc, skMethod, skConverter}:
|
|
addResult(c, result.typ.sons[0], n.info)
|
|
addResultNode(c, n)
|
|
n.sons[codePos] = semStmtScope(c, n.sons[codePos])
|
|
if fn.kind == skIterator:
|
|
# XXX Bad hack for tests/titer2:
|
|
n.sons[codePos] = transform(c.module, n.sons[codePos])
|
|
popProcCon(c)
|
|
#echo "code instantiated ", result.name.s
|
|
else:
|
|
result = oldPrc
|
|
popInfoContext()
|
|
closeScope(c.tab) # close scope for parameters
|
|
popOwner()
|
|
c.module = oldMod
|
|
dec(c.InstCounter)
|
|
|
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
|
var cl: TReplTypeVars
|
|
InitIdTable(cl.symMap)
|
|
InitIdTable(cl.typeMap)
|
|
cl.info = n.info
|
|
cl.c = c
|
|
result = ReplaceTypeVarsT(cl, header)
|
|
|