mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-06 13:07:48 +00:00
bugfix: forwarding of generic procs now works
This commit is contained in:
@@ -585,19 +585,15 @@ proc initFrame(p: BProc, procname, filename: PRope): PRope =
|
||||
proc deinitFrame(p: BProc): PRope =
|
||||
result = ropecg(p.module, "#popFrame();$n")
|
||||
|
||||
proc genProcAux(m: BModule, prc: PSym) =
|
||||
var
|
||||
p: BProc
|
||||
generatedProc, header, returnStmt, procname, filename: PRope
|
||||
res, param: PSym
|
||||
p = newProc(prc, m)
|
||||
header = genProcHeader(m, prc)
|
||||
if (gCmd != cmdCompileToLLVM) and (lfExportLib in prc.loc.flags):
|
||||
proc genProcAux(m: BModule, prc: PSym) =
|
||||
var p = newProc(prc, m)
|
||||
var header = genProcHeader(m, prc)
|
||||
if gCmd != cmdCompileToLLVM and lfExportLib in prc.loc.flags:
|
||||
header = con("N_LIB_EXPORT ", header)
|
||||
returnStmt = nil
|
||||
var returnStmt: PRope = nil
|
||||
assert(prc.ast != nil)
|
||||
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
|
||||
res = prc.ast.sons[resultPos].sym # get result symbol
|
||||
var res = prc.ast.sons[resultPos].sym # get result symbol
|
||||
if not isInvalidReturnType(prc.typ.sons[0]):
|
||||
# declare the result symbol:
|
||||
assignLocalVar(p, res)
|
||||
@@ -611,9 +607,10 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
incl(res.loc.flags, lfIndirect)
|
||||
res.loc.s = OnUnknown
|
||||
for i in countup(1, sonsLen(prc.typ.n) - 1):
|
||||
param = prc.typ.n.sons[i].sym
|
||||
var param = prc.typ.n.sons[i].sym
|
||||
assignParam(p, param)
|
||||
genStmts(p, prc.ast.sons[codePos]) # modifies p.locals, p.init, etc.
|
||||
var generatedProc: PRope
|
||||
if sfPure in prc.flags:
|
||||
generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n",
|
||||
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
|
||||
@@ -622,8 +619,8 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
if optStackTrace in prc.options:
|
||||
getFrameDecl(p)
|
||||
app(generatedProc, p.s[cpsLocals])
|
||||
procname = CStringLit(p, generatedProc, prc.name.s)
|
||||
filename = CStringLit(p, generatedProc, toFilename(prc.info))
|
||||
var procname = CStringLit(p, generatedProc, prc.name.s)
|
||||
var filename = CStringLit(p, generatedProc, toFilename(prc.info))
|
||||
app(generatedProc, initFrame(p, procname, filename))
|
||||
else:
|
||||
app(generatedProc, p.s[cpsLocals])
|
||||
@@ -821,15 +818,14 @@ proc registerModuleToMain(m: PSym) =
|
||||
appff(mainModInit, "$1();$n", "call void ()* $1$n", [initname])
|
||||
|
||||
proc genInitCode(m: BModule) =
|
||||
var initname, prc, procname, filename: PRope
|
||||
if optProfiler in m.initProc.options:
|
||||
# This does not really belong here, but there is no good place for this
|
||||
# code. I don't want to put this to the proc generation as the
|
||||
# ``IncludeStr`` call is quite slow.
|
||||
discard lists.IncludeStr(m.headerFiles, "<cycle.h>")
|
||||
initname = getInitName(m.module)
|
||||
prc = ropeff("N_NOINLINE(void, $1)(void) {$n",
|
||||
"define void $1() noinline {$n", [initname])
|
||||
var initname = getInitName(m.module)
|
||||
var prc = ropeff("N_NOINLINE(void, $1)(void) {$n",
|
||||
"define void $1() noinline {$n", [initname])
|
||||
if m.typeNodes > 0:
|
||||
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
||||
[m.typeNodesName, toRope(m.typeNodes)])
|
||||
@@ -843,8 +839,8 @@ proc genInitCode(m: BModule) =
|
||||
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
|
||||
app(prc, m.initProc.s[cpsLocals])
|
||||
app(prc, m.s[cfsTypeInit1])
|
||||
procname = CStringLit(m.initProc, prc, m.module.name.s)
|
||||
filename = CStringLit(m.initProc, prc, toFilename(m.module.info))
|
||||
var procname = CStringLit(m.initProc, prc, m.module.name.s)
|
||||
var filename = CStringLit(m.initProc, prc, toFilename(m.module.info))
|
||||
app(prc, initFrame(m.initProc, procname, filename))
|
||||
else:
|
||||
app(prc, m.initProc.s[cpsLocals])
|
||||
@@ -940,7 +936,8 @@ proc finishModule(m: BModule) =
|
||||
# Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
|
||||
# a ``for`` loop here
|
||||
var prc = m.forwardedProcs[i]
|
||||
if sfForward in prc.flags: InternalError(prc.info, "still forwarded")
|
||||
if sfForward in prc.flags:
|
||||
InternalError(prc.info, "still forwarded: " & prc.name.s)
|
||||
genProcNoForward(m, prc)
|
||||
inc(i)
|
||||
assert(gForwardedProcsCounter >= i)
|
||||
|
||||
@@ -49,7 +49,7 @@ proc getSymRepr*(s: PSym): string =
|
||||
|
||||
proc CloseScope*(tab: var TSymTab) =
|
||||
# check if all symbols have been used and defined:
|
||||
if (tab.tos > len(tab.stack)): InternalError("CloseScope")
|
||||
if tab.tos > len(tab.stack): InternalError("CloseScope")
|
||||
var it: TTabIter
|
||||
var s = InitTabIter(it, tab.stack[tab.tos-1])
|
||||
while s != nil:
|
||||
|
||||
@@ -65,6 +65,35 @@ proc removeDefaultParamValues(n: PNode) =
|
||||
# not possible... XXX We don't solve this issue here.
|
||||
a.sons[L-1] = ast.emptyNode
|
||||
|
||||
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||
if n.sons[codePos].kind != nkEmpty:
|
||||
# add it here, so that recursive generic procs are possible:
|
||||
addDecl(c, result)
|
||||
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 result.kind == skIterator:
|
||||
# XXX Bad hack for tests/titer2:
|
||||
n.sons[codePos] = transform(c.module, n.sons[codePos])
|
||||
#echo "code instantiated ", result.name.s
|
||||
excl(result.flags, sfForward)
|
||||
popProcCon(c)
|
||||
|
||||
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||
for i in countup(0, Len(generics) - 1):
|
||||
if generics[i].genericSym.id == s.id:
|
||||
var oldPrc = generics[i].instSym
|
||||
pushInfoContext(oldPrc.info)
|
||||
openScope(c.tab)
|
||||
var n = oldPrc.ast
|
||||
n.sons[codePos] = copyTree(s.ast.sons[codePos])
|
||||
if n.sons[paramsPos].kind != nkEmpty: addParams(c, oldPrc.typ.n)
|
||||
instantiateBody(c, n, oldPrc)
|
||||
closeScope(c.tab)
|
||||
popInfoContext()
|
||||
|
||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
info: TLineInfo): PSym =
|
||||
# generates an instantiated proc
|
||||
@@ -103,20 +132,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
ParamsTypeCheck(c, result.typ)
|
||||
var oldPrc = GenericCacheGet(c, entry)
|
||||
if oldPrc == nil:
|
||||
# add it here, so that recursive generic procs are possible:
|
||||
generics.add(entry)
|
||||
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
|
||||
instantiateBody(c, n, result)
|
||||
else:
|
||||
result = oldPrc
|
||||
popInfoContext()
|
||||
|
||||
@@ -397,7 +397,7 @@ proc semRaise(c: PContext, n: PNode): PNode =
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||
var typ = n.sons[0].typ
|
||||
if (typ.kind != tyRef) or (typ.sons[0].kind != tyObject):
|
||||
if typ.kind != tyRef or typ.sons[0].kind != tyObject:
|
||||
localError(n.info, errExprCannotBeRaised)
|
||||
|
||||
proc semTry(c: PContext, n: PNode): PNode =
|
||||
@@ -593,9 +593,6 @@ proc semLambda(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
validPragmas: TSpecialWords): PNode =
|
||||
var
|
||||
proto: PSym
|
||||
gp: PNode
|
||||
result = n
|
||||
checkSonsLen(n, codePos + 1)
|
||||
var s = semIdentDef(c, n.sons[0], kind)
|
||||
@@ -604,6 +601,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
s.ast = n
|
||||
pushOwner(s)
|
||||
openScope(c.tab)
|
||||
var gp: PNode
|
||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||
gp = n.sons[genericParamsPos]
|
||||
@@ -622,8 +620,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
else:
|
||||
s.typ = newTypeS(tyProc, c)
|
||||
addSon(s.typ, nil)
|
||||
proto = SearchForProc(c, s, c.tab.tos - 2) # -2 because we have a scope open
|
||||
# for parameters
|
||||
var proto = SearchForProc(c, s, c.tab.tos-2) # -2 because we have a scope
|
||||
# open for parameters
|
||||
if proto == nil:
|
||||
if c.p.owner.kind != skModule:
|
||||
s.typ.callConv = ccClosure
|
||||
@@ -666,7 +664,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
ParamsTypeCheck(c, s.typ)
|
||||
pushProcCon(c, s)
|
||||
if (s.typ.sons[0] != nil) and (kind != skIterator):
|
||||
if s.typ.sons[0] != nil and kind != skIterator:
|
||||
addResult(c, s.typ.sons[0], n.info)
|
||||
if sfImportc notin s.flags:
|
||||
# no semantic checking for importc:
|
||||
@@ -677,6 +675,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
if s.typ.sons[0] != nil and kind != skIterator:
|
||||
addDecl(c, newSym(skUnknown, getIdent("result"), nil))
|
||||
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], {})
|
||||
fixupInstantiatedSymbols(c, s)
|
||||
if sfImportc in s.flags:
|
||||
# so we just ignore the body after semantic checking for importc:
|
||||
n.sons[codePos] = ast.emptyNode
|
||||
@@ -744,7 +743,7 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||
|
||||
proc evalInclude(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
addSon(result, n) # the rodwriter needs include information!
|
||||
addSon(result, n)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var f = getModuleFile(n.sons[i])
|
||||
var fileIndex = includeFilename(f)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
Comex
|
||||
Eric Doughty-Papassideris
|
||||
Keita Haga
|
||||
Philippe Lhoste
|
||||
Mario Ray Mahardhika
|
||||
Alex Mitchell
|
||||
|
||||
11
tests/accept/compile/tforwardgeneric.nim
Normal file
11
tests/accept/compile/tforwardgeneric.nim
Normal file
@@ -0,0 +1,11 @@
|
||||
discard """
|
||||
output: "1.0000000000000000e+00 10"
|
||||
"""
|
||||
|
||||
proc p[T](a, b: T): T
|
||||
|
||||
echo p(0.9, 0.1), " ", p(9, 1)
|
||||
|
||||
proc p[T](a, b: T): T =
|
||||
result = a + b
|
||||
|
||||
2
todo.txt
2
todo.txt
@@ -18,7 +18,6 @@ version 0.9.0
|
||||
=============
|
||||
|
||||
- add --deadlock_prevention:on|off switch? timeout for locks?
|
||||
- bug: forward proc for generic seems broken
|
||||
- warning for implicit openArray -> varargs convention
|
||||
- implement explicit varargs
|
||||
- tests: run modules that contain "#RUN_ME", compile the other
|
||||
@@ -31,6 +30,7 @@ Bugs
|
||||
- bug: generic assign still buggy
|
||||
- Optimization: If we use a temporary for the result anyway the code gen
|
||||
should make use of this fact to generate better code...
|
||||
- bug: memset() without type field initialization?
|
||||
- special case the generic assign that needs to care about case objects
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ Bugfixes
|
||||
- Fixed a serious bug concerning different instantiations of a generic proc.
|
||||
- Fixed a newly introduced bug where a wrong ``EIO`` exception was raised for
|
||||
the end of file for text files that do not end with a newline.
|
||||
- Bugfix c2nim, c2pas: the ``--out`` option has never worked properly.
|
||||
- Bugfix: forwarding of generic procs never worked.
|
||||
|
||||
|
||||
Changes affecting backwards compatibility
|
||||
|
||||
Reference in New Issue
Block a user