diff options
-rw-r--r-- | compiler/lambdalifting.nim | 22 | ||||
-rw-r--r-- | tests/closure/tinfer_closure_for_nestedproc.nim | 42 |
2 files changed, 62 insertions, 2 deletions
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index e72cd5bd1..874cb4bd0 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -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 diff --git a/tests/closure/tinfer_closure_for_nestedproc.nim b/tests/closure/tinfer_closure_for_nestedproc.nim new file mode 100644 index 000000000..6450d1492 --- /dev/null +++ b/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()) |