Fix forward declaration issues in template/macro context (#15091)

* Fix forward declaration issues in template/macro context

* Correct forward declaration resolving for overloads

* Remove old dead code

* WIP consistent gensym ids

* Minimize diff

* Remove obsoleted hack

* Add templInstCounter to give unique IDs to template instantiations

* Remove obsoleted code

* Eh, init in myOpen, not myProcess...

* Remove optNimV019

* Add testcase for #13484
This commit is contained in:
Clyybber 2020-07-29 16:17:20 +02:00 • committed by GitHub
commit 2629d619a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 270 additions and 95 deletions

View file

@ -35,6 +35,10 @@ test
foo1
foo2
foo3
true
false
true
false
'''
"""
@ -289,3 +293,113 @@ proc main() =
const fb = Foobar(a: a)
foobar(fb)
main()
# bug #13484
proc defForward(id, nid: NimNode): NimNode =
result = newProc(id, @[newIdentNode("bool"), newIdentDefs(nid, newIdentNode("int"))], body=newEmptyNode())
proc defEven(evenid, oddid, nid: NimNode): NimNode =
result = quote do:
proc `evenid`(`nid`: int): bool =
if `nid` == 0:
return true
else:
return `oddid`(`nid` - 1)
proc defOdd(evenid, oddid, nid: NimNode): NimNode =
result = quote do:
proc `oddid`(`nid`: int): bool =
if `nid` == 0:
return false
else:
return `evenid`(`nid` - 1)
proc callNode(funid, param: NimNode): NimNode =
result = quote do:
`funid`(`param`)
macro testEvenOdd3(): untyped =
let
evenid = newIdentNode("even3")
oddid = newIdentNode("odd3")
nid = newIdentNode("n")
oddForward = defForward(oddid, nid)
even = defEven(evenid, oddid, nid)
odd = defOdd(evenid, oddid, nid)
callEven = callNode(evenid, newLit(42))
callOdd = callNode(oddid, newLit(42))
result = quote do:
`oddForward`
`even`
`odd`
echo `callEven`
echo `callOdd`
macro testEvenOdd4(): untyped =
let
evenid = newIdentNode("even4")
oddid = newIdentNode("odd4")
nid = newIdentNode("n")
oddForward = defForward(oddid, nid)
even = defEven(evenid, oddid, nid)
odd = defOdd(evenid, oddid, nid)
callEven = callNode(evenid, newLit(42))
callOdd = callNode(oddid, newLit(42))
# rewrite the body of proc node.
oddForward[6] = newStmtList()
result = quote do:
`oddForward`
`even`
`odd`
echo `callEven`
echo `callOdd`
macro testEvenOdd5(): untyped =
let
evenid = genSym(nskProc, "even5")
oddid = genSym(nskProc, "odd5")
nid = newIdentNode("n")
oddForward = defForward(oddid, nid)
even = defEven(evenid, oddid, nid)
odd = defOdd(evenid, oddid, nid)
callEven = callNode(evenid, newLit(42))
callOdd = callNode(oddid, newLit(42))
result = quote do:
`oddForward`
`even`
`odd`
echo `callEven`
echo `callOdd`
macro testEvenOdd6(): untyped =
let
evenid = genSym(nskProc, "even6")
oddid = genSym(nskProc, "odd6")
nid = newIdentNode("n")
oddForward = defForward(oddid, nid)
even = defEven(evenid, oddid, nid)
odd = defOdd(evenid, oddid, nid)
callEven = callNode(evenid, newLit(42))
callOdd = callNode(oddid, newLit(42))
# rewrite the body of proc node.
oddForward[6] = newStmtList()
result = quote do:
`oddForward`
`even`
`odd`
echo `callEven`
echo `callOdd`
# it works
testEvenOdd3()
# it causes an error (redefinition of odd4), which is correct
assert not compiles testEvenOdd4()
# it caused an error (still forwarded: odd5)
testEvenOdd5()
# it works, because the forward decl and definition share the symbol and the compiler is forgiving here
#testEvenOdd6() #Don't test it though, the compiler may become more strict in the future

View file

@ -195,3 +195,129 @@ mystate_machine:
state_push(S1)
echo state_current()
state_pop()
# bug #15075
block: #Doesn't work
template genGenTempl: untyped =
proc loop(locals: int)
proc loop(locals: int) = discard
genGenTempl()
let pool = loop
block: #Doesn't work
macro genGenMacro: untyped =
quote do:
proc loop(locals: int)
proc loop(locals: int) = discard
genGenMacro()
let pool = loop
block: #This works
proc loop(locals: int)
proc loop(locals: int) = discard
let pool = loop
#Now somewhat recursive:
type Cont = ref object of RootObj
fn*: proc(c: Cont): Cont {.nimcall.}
block: #Doesn't work
template genGenTempl(): untyped =
proc loop(locals: Cont): Cont
proc loop(locals: Cont): Cont =
return Cont(fn: loop)
proc doServer(): Cont =
return Cont(fn: loop)
genGenTempl()
discard doServer()
block: #Doesn't work
macro genGenMacro(): untyped =
quote:
proc loop(locals: Cont): Cont
proc loop(locals: Cont): Cont =
return Cont(fn: loop)
proc doServer(): Cont =
return Cont(fn: loop)
genGenMacro()
discard doServer()
block: #This works
proc loop(locals: Cont): Cont
proc loop(locals: Cont): Cont =
return Cont(fn: loop)
proc doServer(): Cont =
return Cont(fn: loop)
discard doServer()
#And fully recursive:
block: #Doesn't work
template genGenTempl: untyped =
proc loop(locals: int)
proc loop(locals: int) = loop(locals)
genGenTempl()
let pool = loop
block: #Doesn't work
macro genGenMacro: untyped =
quote do:
proc loop(locals: int)
proc loop(locals: int) = loop(locals)
genGenMacro()
let pool = loop
block: #This works
proc loop(locals: int)
proc loop(locals: int) = loop(locals)
let pool = loop
block:
template genAndCallLoop: untyped =
proc loop() {.gensym.}
proc loop() {.gensym.} =
discard
loop()
genAndCallLoop
block: #Fully recursive and gensymmed:
template genGenTempl: untyped =
proc loop(locals: int) {.gensym.}
proc loop(locals: int) {.gensym.} = loop(locals)
let pool = loop
genGenTempl()
block: #Make sure gensymmed symbol doesn't overwrite the forward decl
proc loop()
proc loop() = discard
template genAndCallLoop: untyped =
proc loop() {.gensym.} =
discard
loop()
genAndCallLoop()
template genLoopDecl: untyped =
proc loop()
template genLoopDef: untyped =
proc loop() = discard
block:
genLoopDecl
genLoopDef
loop()
block:
proc loop()
genLoopDef
loop()
block:
genLoopDecl
proc loop() = discard
loop()
block: #Gensymmed sym sharing forward decl
macro genGenMacro: untyped =
let sym = genSym(nskProc, "loop")
nnkStmtList.newTree(
newProc(sym, body = newEmptyNode()),
newCall(sym),
newProc(sym, body = newStmtList()),
)
genGenMacro