bugfix: forwarding of generic procs now works
This commit is contained in:
parent
dce8949b9b
commit
6781da5215
8 changed files with 70 additions and 43 deletions
|
|
@ -586,18 +586,14 @@ proc deinitFrame(p: BProc): PRope =
|
||||||
result = ropecg(p.module, "#popFrame();$n")
|
result = ropecg(p.module, "#popFrame();$n")
|
||||||
|
|
||||||
proc genProcAux(m: BModule, prc: PSym) =
|
proc genProcAux(m: BModule, prc: PSym) =
|
||||||
var
|
var p = newProc(prc, m)
|
||||||
p: BProc
|
var header = genProcHeader(m, prc)
|
||||||
generatedProc, header, returnStmt, procname, filename: PRope
|
if gCmd != cmdCompileToLLVM and lfExportLib in prc.loc.flags:
|
||||||
res, param: PSym
|
|
||||||
p = newProc(prc, m)
|
|
||||||
header = genProcHeader(m, prc)
|
|
||||||
if (gCmd != cmdCompileToLLVM) and (lfExportLib in prc.loc.flags):
|
|
||||||
header = con("N_LIB_EXPORT ", header)
|
header = con("N_LIB_EXPORT ", header)
|
||||||
returnStmt = nil
|
var returnStmt: PRope = nil
|
||||||
assert(prc.ast != nil)
|
assert(prc.ast != nil)
|
||||||
if sfPure notin prc.flags and prc.typ.sons[0] != 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]):
|
if not isInvalidReturnType(prc.typ.sons[0]):
|
||||||
# declare the result symbol:
|
# declare the result symbol:
|
||||||
assignLocalVar(p, res)
|
assignLocalVar(p, res)
|
||||||
|
|
@ -611,9 +607,10 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||||
incl(res.loc.flags, lfIndirect)
|
incl(res.loc.flags, lfIndirect)
|
||||||
res.loc.s = OnUnknown
|
res.loc.s = OnUnknown
|
||||||
for i in countup(1, sonsLen(prc.typ.n) - 1):
|
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)
|
assignParam(p, param)
|
||||||
genStmts(p, prc.ast.sons[codePos]) # modifies p.locals, p.init, etc.
|
genStmts(p, prc.ast.sons[codePos]) # modifies p.locals, p.init, etc.
|
||||||
|
var generatedProc: PRope
|
||||||
if sfPure in prc.flags:
|
if sfPure in prc.flags:
|
||||||
generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n",
|
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]])
|
[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:
|
if optStackTrace in prc.options:
|
||||||
getFrameDecl(p)
|
getFrameDecl(p)
|
||||||
app(generatedProc, p.s[cpsLocals])
|
app(generatedProc, p.s[cpsLocals])
|
||||||
procname = CStringLit(p, generatedProc, prc.name.s)
|
var procname = CStringLit(p, generatedProc, prc.name.s)
|
||||||
filename = CStringLit(p, generatedProc, toFilename(prc.info))
|
var filename = CStringLit(p, generatedProc, toFilename(prc.info))
|
||||||
app(generatedProc, initFrame(p, procname, filename))
|
app(generatedProc, initFrame(p, procname, filename))
|
||||||
else:
|
else:
|
||||||
app(generatedProc, p.s[cpsLocals])
|
app(generatedProc, p.s[cpsLocals])
|
||||||
|
|
@ -821,15 +818,14 @@ proc registerModuleToMain(m: PSym) =
|
||||||
appff(mainModInit, "$1();$n", "call void ()* $1$n", [initname])
|
appff(mainModInit, "$1();$n", "call void ()* $1$n", [initname])
|
||||||
|
|
||||||
proc genInitCode(m: BModule) =
|
proc genInitCode(m: BModule) =
|
||||||
var initname, prc, procname, filename: PRope
|
|
||||||
if optProfiler in m.initProc.options:
|
if optProfiler in m.initProc.options:
|
||||||
# This does not really belong here, but there is no good place for this
|
# 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
|
# code. I don't want to put this to the proc generation as the
|
||||||
# ``IncludeStr`` call is quite slow.
|
# ``IncludeStr`` call is quite slow.
|
||||||
discard lists.IncludeStr(m.headerFiles, "<cycle.h>")
|
discard lists.IncludeStr(m.headerFiles, "<cycle.h>")
|
||||||
initname = getInitName(m.module)
|
var initname = getInitName(m.module)
|
||||||
prc = ropeff("N_NOINLINE(void, $1)(void) {$n",
|
var prc = ropeff("N_NOINLINE(void, $1)(void) {$n",
|
||||||
"define void $1() noinline {$n", [initname])
|
"define void $1() noinline {$n", [initname])
|
||||||
if m.typeNodes > 0:
|
if m.typeNodes > 0:
|
||||||
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
||||||
[m.typeNodesName, toRope(m.typeNodes)])
|
[m.typeNodesName, toRope(m.typeNodes)])
|
||||||
|
|
@ -843,8 +839,8 @@ proc genInitCode(m: BModule) =
|
||||||
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
|
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
|
||||||
app(prc, m.initProc.s[cpsLocals])
|
app(prc, m.initProc.s[cpsLocals])
|
||||||
app(prc, m.s[cfsTypeInit1])
|
app(prc, m.s[cfsTypeInit1])
|
||||||
procname = CStringLit(m.initProc, prc, m.module.name.s)
|
var procname = CStringLit(m.initProc, prc, m.module.name.s)
|
||||||
filename = CStringLit(m.initProc, prc, toFilename(m.module.info))
|
var filename = CStringLit(m.initProc, prc, toFilename(m.module.info))
|
||||||
app(prc, initFrame(m.initProc, procname, filename))
|
app(prc, initFrame(m.initProc, procname, filename))
|
||||||
else:
|
else:
|
||||||
app(prc, m.initProc.s[cpsLocals])
|
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
|
# Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
|
||||||
# a ``for`` loop here
|
# a ``for`` loop here
|
||||||
var prc = m.forwardedProcs[i]
|
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)
|
genProcNoForward(m, prc)
|
||||||
inc(i)
|
inc(i)
|
||||||
assert(gForwardedProcsCounter >= i)
|
assert(gForwardedProcsCounter >= i)
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ proc getSymRepr*(s: PSym): string =
|
||||||
|
|
||||||
proc CloseScope*(tab: var TSymTab) =
|
proc CloseScope*(tab: var TSymTab) =
|
||||||
# check if all symbols have been used and defined:
|
# 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 it: TTabIter
|
||||||
var s = InitTabIter(it, tab.stack[tab.tos-1])
|
var s = InitTabIter(it, tab.stack[tab.tos-1])
|
||||||
while s != nil:
|
while s != nil:
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,35 @@ proc removeDefaultParamValues(n: PNode) =
|
||||||
# not possible... XXX We don't solve this issue here.
|
# not possible... XXX We don't solve this issue here.
|
||||||
a.sons[L-1] = ast.emptyNode
|
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,
|
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
info: TLineInfo): PSym =
|
info: TLineInfo): PSym =
|
||||||
# generates an instantiated proc
|
# generates an instantiated proc
|
||||||
|
|
@ -103,20 +132,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
ParamsTypeCheck(c, result.typ)
|
ParamsTypeCheck(c, result.typ)
|
||||||
var oldPrc = GenericCacheGet(c, entry)
|
var oldPrc = GenericCacheGet(c, entry)
|
||||||
if oldPrc == nil:
|
if oldPrc == nil:
|
||||||
# add it here, so that recursive generic procs are possible:
|
|
||||||
generics.add(entry)
|
generics.add(entry)
|
||||||
addDecl(c, result)
|
instantiateBody(c, n, 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:
|
else:
|
||||||
result = oldPrc
|
result = oldPrc
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
|
|
|
||||||
|
|
@ -397,7 +397,7 @@ proc semRaise(c: PContext, n: PNode): PNode =
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0])
|
n.sons[0] = semExprWithType(c, n.sons[0])
|
||||||
var typ = n.sons[0].typ
|
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)
|
localError(n.info, errExprCannotBeRaised)
|
||||||
|
|
||||||
proc semTry(c: PContext, n: PNode): PNode =
|
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,
|
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
validPragmas: TSpecialWords): PNode =
|
validPragmas: TSpecialWords): PNode =
|
||||||
var
|
|
||||||
proto: PSym
|
|
||||||
gp: PNode
|
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, codePos + 1)
|
checkSonsLen(n, codePos + 1)
|
||||||
var s = semIdentDef(c, n.sons[0], kind)
|
var s = semIdentDef(c, n.sons[0], kind)
|
||||||
|
|
@ -604,6 +601,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
s.ast = n
|
s.ast = n
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
openScope(c.tab)
|
openScope(c.tab)
|
||||||
|
var gp: PNode
|
||||||
if n.sons[genericParamsPos].kind != nkEmpty:
|
if n.sons[genericParamsPos].kind != nkEmpty:
|
||||||
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
n.sons[genericParamsPos] = semGenericParamList(c, n.sons[genericParamsPos])
|
||||||
gp = n.sons[genericParamsPos]
|
gp = n.sons[genericParamsPos]
|
||||||
|
|
@ -622,8 +620,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
else:
|
else:
|
||||||
s.typ = newTypeS(tyProc, c)
|
s.typ = newTypeS(tyProc, c)
|
||||||
addSon(s.typ, nil)
|
addSon(s.typ, nil)
|
||||||
proto = SearchForProc(c, s, c.tab.tos - 2) # -2 because we have a scope open
|
var proto = SearchForProc(c, s, c.tab.tos-2) # -2 because we have a scope
|
||||||
# for parameters
|
# open for parameters
|
||||||
if proto == nil:
|
if proto == nil:
|
||||||
if c.p.owner.kind != skModule:
|
if c.p.owner.kind != skModule:
|
||||||
s.typ.callConv = ccClosure
|
s.typ.callConv = ccClosure
|
||||||
|
|
@ -666,7 +664,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||||
ParamsTypeCheck(c, s.typ)
|
ParamsTypeCheck(c, s.typ)
|
||||||
pushProcCon(c, s)
|
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)
|
addResult(c, s.typ.sons[0], n.info)
|
||||||
if sfImportc notin s.flags:
|
if sfImportc notin s.flags:
|
||||||
# no semantic checking for importc:
|
# 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:
|
if s.typ.sons[0] != nil and kind != skIterator:
|
||||||
addDecl(c, newSym(skUnknown, getIdent("result"), nil))
|
addDecl(c, newSym(skUnknown, getIdent("result"), nil))
|
||||||
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], {})
|
n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], {})
|
||||||
|
fixupInstantiatedSymbols(c, s)
|
||||||
if sfImportc in s.flags:
|
if sfImportc in s.flags:
|
||||||
# so we just ignore the body after semantic checking for importc:
|
# so we just ignore the body after semantic checking for importc:
|
||||||
n.sons[codePos] = ast.emptyNode
|
n.sons[codePos] = ast.emptyNode
|
||||||
|
|
@ -744,7 +743,7 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
proc evalInclude(c: PContext, n: PNode): PNode =
|
proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
result = newNodeI(nkStmtList, n.info)
|
result = newNodeI(nkStmtList, n.info)
|
||||||
addSon(result, n) # the rodwriter needs include information!
|
addSon(result, n)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var f = getModuleFile(n.sons[i])
|
var f = getModuleFile(n.sons[i])
|
||||||
var fileIndex = includeFilename(f)
|
var fileIndex = includeFilename(f)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
Comex
|
Comex
|
||||||
Eric Doughty-Papassideris
|
Eric Doughty-Papassideris
|
||||||
|
Keita Haga
|
||||||
Philippe Lhoste
|
Philippe Lhoste
|
||||||
Mario Ray Mahardhika
|
Mario Ray Mahardhika
|
||||||
Alex Mitchell
|
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?
|
- add --deadlock_prevention:on|off switch? timeout for locks?
|
||||||
- bug: forward proc for generic seems broken
|
|
||||||
- warning for implicit openArray -> varargs convention
|
- warning for implicit openArray -> varargs convention
|
||||||
- implement explicit varargs
|
- implement explicit varargs
|
||||||
- tests: run modules that contain "#RUN_ME", compile the other
|
- tests: run modules that contain "#RUN_ME", compile the other
|
||||||
|
|
@ -31,6 +30,7 @@ Bugs
|
||||||
- bug: generic assign still buggy
|
- bug: generic assign still buggy
|
||||||
- Optimization: If we use a temporary for the result anyway the code gen
|
- Optimization: If we use a temporary for the result anyway the code gen
|
||||||
should make use of this fact to generate better code...
|
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
|
- 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 serious bug concerning different instantiations of a generic proc.
|
||||||
- Fixed a newly introduced bug where a wrong ``EIO`` exception was raised for
|
- 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.
|
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
|
Changes affecting backwards compatibility
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue