Skip to content

Commit 5da0253

Browse files
committed
lambdalifting: fix capturing macro parameters not working
Summary ======= Fix macro parameters used in an inner procedure being reset to their type's default value upon entering the macro. Details ======= Macros have an external and an internal signature. All parameter symbols in the body refer to parameters belonging to the internal signature, but when generating the env construction, `rawClosureCreation` only considered the external signature. The consequence was that lifted parameters were not initialized. `rawClosureCreation` now uses the internal signature when generating the env setup, fixing the issue. In addition `rawClosureCreation` creation is refactored: * the doc comment is changed to match reality * the `isIterator` case is removed, since `rawClosureCreation` is never called for iterators * all env fields are initialized directly by the constructor expression, instead of via separate assignments * the procedure only returns a `var` statement AST now
1 parent 8456d2e commit 5da0253

File tree

2 files changed

+38
-42
lines changed

2 files changed

+38
-42
lines changed

compiler/sem/lambdalifting.nim

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -216,16 +216,6 @@ proc isInnerProc(s: PSym): bool =
216216
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
217217
result = s.skipGenericOwner.kind in routineKinds
218218

219-
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
220-
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
221-
# mean to be able to capture string literals which have no GC header.
222-
# However this can only happen if the capture happens through a parameter,
223-
# which is however the only case when we generate an assignment in the first
224-
# place.
225-
result = newNodeI(nkAsgn, info, 2)
226-
result[0] = le
227-
result[1] = ri
228-
229219
proc makeClosure*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; env: PNode; info: TLineInfo): PNode =
230220
result = newNodeIT(nkClosure, info, prc.typ)
231221
result.add(newSymNode(prc))
@@ -533,41 +523,36 @@ proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
533523

534524
proc rawClosureCreation(graph: ModuleGraph, idgen: IdGenerator,
535525
c: LiftingPass; info: TLineInfo): PNode =
536-
## Generates and returns the AST for allocating and setting up an instance
537-
## of `owner`'s lifted local environment.
538-
result = newNodeI(nkStmtList, c.owner.info)
539-
540-
var env: PNode
541-
if c.owner.isIterator:
542-
env = newSymNode(c.envSym)
543-
else:
544-
env = newSymNode(c.envSym)
545-
let v = newTreeI(nkVarSection, env.info):
546-
newIdentDefs(env, newObjConstr(env.typ, info))
547-
result.add(v)
548-
549-
# add assignment statements for captured parameters:
550-
for i in 1..<c.owner.typ.n.len:
551-
let local = c.owner.typ.n[i].sym
552-
if local.id in c.capturedVars:
553-
let fieldAccess = indirectAccess(env, local, env.info)
554-
# add ``env.param = param``
555-
result.add(newAsgnStmt(fieldAccess, newSymNode(local), env.info))
556-
if c.owner.kind != skMacro:
557-
createTypeBoundOps(graph, nil, fieldAccess.typ, env.info, idgen)
558-
if tfHasAsgn in fieldAccess.typ.flags or optSeqDestructors in graph.config.globalOptions:
559-
c.owner.flags.incl sfInjectDestructors
560-
561-
let upField = lookupInRecord(
562-
env.typ.base.n, getIdent(graph.cache, upName))
563-
526+
## Generates and returns the var statement AST for constructing an instance
527+
## of the local environment object.
528+
let
529+
typ = c.envSym.typ
530+
constr = newObjConstr(typ, info)
531+
signature = if c.owner.kind == skMacro: c.owner.internal
532+
else: c.owner.typ
533+
534+
# add the initialization for captured parameters to the construction:
535+
for i in 1..<signature.n.len:
536+
let param = signature.n[i].sym
537+
if param.id in c.capturedVars:
538+
let field = getFieldFromObj(typ.base, param)
539+
constr.add(newTree(nkExprColonExpr, newSymNode(field), newSymNode(param)))
540+
if c.owner.kind != skMacro:
541+
createTypeBoundOps(graph, nil, field.typ, c.envSym.info, idgen)
542+
if tfHasAsgn in field.typ.flags or
543+
optSeqDestructors in graph.config.globalOptions:
544+
c.owner.flags.incl sfInjectDestructors
545+
546+
let upField = lookupInRecord(typ.base.n, getIdent(graph.cache, upName))
564547
if upField != nil:
565548
let up = getUpViaParam(graph, c.owner)
566549
graph.config.internalAssert(
567550
up != nil and upField.typ.base == up.typ.base,
568-
env.info, "internal error: cannot create up reference")
551+
c.envSym.info, "internal error: cannot create up reference")
552+
553+
constr.add(newTree(nkExprColonExpr, newSymNode(upField), up))
569554

570-
result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info), up, env.info))
555+
result = newTree(nkVarSection, newIdentDefs(newSymNode(c.envSym), constr))
571556

572557
proc accessViaEnvVar(n: PNode; c: LiftingPass): PNode =
573558
let access = newSymNode(c.envSym)
@@ -791,7 +776,8 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode;
791776
let t = produceEnvType(d, idgen, fn, fn.info)
792777
prepareInnerRoutines(d, idgen, t, fn.info)
793778
let c = initLiftingPass(d, newEnvVar(g.cache, fn, t, fn.info, idgen))
794-
result = rawClosureCreation(g, idgen, c, body.info)
779+
result = newTreeI(nkStmtList, body.info)
780+
result.add rawClosureCreation(g, idgen, c, body.info)
795781
result.add liftCapturedVars(body, g, idgen, c)
796782
elif d.requireUp or d.accessOuter:
797783
# the procedure only access the env parameter, without creating its

tests/lang_callable/closure/tclosure.nim

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,4 +611,14 @@ block use_closure_iterator_via_for_syntax:
611611
doAssert it == compare
612612
inc compare
613613

614-
outer()
614+
outer()
615+
616+
block close_over_macro_params:
617+
# macro parameters may be closed over like any other routine parameters
618+
macro m(x: static int, y: int) =
619+
proc inner() =
620+
doAssert x == 1
621+
doAssert not y.isNil
622+
inner()
623+
624+
m(1, 2)

0 commit comments

Comments
 (0)