Skip to content

Commit

Permalink
fixes #9441
Browse files Browse the repository at this point in the history
  • Loading branch information
Araq committed Dec 6, 2018
1 parent 467274a commit 7a0191a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 2 deletions.
22 changes: 20 additions & 2 deletions compiler/lambdalifting.nim
Expand Up @@ -718,19 +718,37 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
# ------------------ old stuff -------------------------------------------

proc semCaptureSym*(s, owner: PSym) =
discard """
proc outer() =
var x: int
proc inner() =
proc innerInner() =
echo x
innerInner()
inner()
# inner() takes a closure too!
"""
proc propagateClosure(start, last: PSym) =
var o = start
while o != nil and o.kind != skModule:
if o == last: break
o.typ.callConv = ccClosure
o = o.skipGenericOwner

if interestingVar(s) and s.kind != skResult:
if owner.typ != nil and not isGenericRoutine(owner):
# XXX: is this really safe?
# if we capture a var from another generic routine,
# it won't be consider captured.
var o = owner.skipGenericOwner
while o.kind != skModule and o != nil:
while o != nil and o.kind != skModule:
if s.owner == o:
if owner.typ.callConv in {ccClosure, ccDefault} or owner.kind == skIterator:
owner.typ.callConv = ccClosure
propagateClosure(owner.skipGenericOwner, s.owner)
else:
discard "do not produce an error here, but later"
#echo "computing .closure for ", owner.name.s, " ", owner.info, " because of ", s.name.s
#echo "computing .closure for ", owner.name.s, " because of ", s.name.s
o = o.skipGenericOwner
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
# here
Expand Down
42 changes: 42 additions & 0 deletions tests/closure/tinfer_closure_for_nestedproc.nim
@@ -0,0 +1,42 @@
discard """
action: compile
"""

# bug #9441
import asyncdispatch, asyncfutures, strtabs

type
Request = object
Context = object
position: int
accept: bool
headers: StringTableRef
Handler = proc (r: ref Request, c: Context): Future[Context]

proc respond(req: Request): Future[void] = discard

proc handle*(h: Handler): auto = # (proc (req: Request): Future[void]) =
proc server(req: Request): Future[void] {.async.} =
let emptyCtx = Context(
position: 0,
accept: true,
headers: newStringTable()
)
var reqHeap = new(Request)
reqHeap[] = req
var
f: Future[Context]
ctx: Context
try:
f = h(reqHeap, emptyCtx)
ctx = await f
except:
discard
if f.failed:
await req.respond()
else:
if not ctx.accept:
await req.respond()
return server

waitFor handle(nil)(Request())

0 comments on commit 7a0191a

Please sign in to comment.