diff --git a/compiler/semfields.nim b/compiler/semfields.nim index 874055cdcde9..7e2f5d6fdd5b 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -18,6 +18,15 @@ type replaceByFieldName: bool c: PContext +proc wrapNewScope(c: PContext, n: PNode): PNode {.inline.} = + # use `if true` to not interfere with `break` + # just opening scope via `openScope(c)` isn't enough, + # a scope has to be opened in the codegen as well for reused + # template instantiations + let trueLit = newIntLit(c.graph, n.info, 1) + trueLit.typ() = getSysType(c.graph, n.info, tyBool) + result = newTreeI(nkIfStmt, n.info, newTreeI(nkElifBranch, n.info, trueLit, n)) + proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = if c.field != nil and isEmptyType(c.field.typ): result = newNode(nkEmpty) @@ -72,7 +81,9 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = ) openScope(c.c) inc c.c.inUnrolledContext - let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) + var body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) + # new scope for each field that codegen should know about: + body = wrapNewScope(c.c, body) father.add(semStmt(c.c, body, {})) dec c.c.inUnrolledContext closeScope(c.c) @@ -148,6 +159,8 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = replaceByFieldName: m == mFieldPairs ) var body = instFieldLoopBody(fc, loopBody, n) + # new scope for each field that codegen should know about: + body = wrapNewScope(c, body) inc c.inUnrolledContext stmts.add(semStmt(c, body, {})) dec c.inUnrolledContext diff --git a/tests/system/tfields.nim b/tests/system/tfields.nim index 0bf3a4e1adf0..8e7533baacdf 100644 --- a/tests/system/tfields.nim +++ b/tests/system/tfields.nim @@ -105,4 +105,48 @@ block timplicit_with_partial: echo x echo x - foo(FooTask()) \ No newline at end of file + foo(FooTask()) + +block: # issue #24338 + var innerCount = 0 + var outerCount = 0 + template c(w: int): int = + let q = w + inc innerCount + 0 + + template t(r: (int, int); x: int) = + for _ in r.fields: + let w = x + doAssert w == 0 + dec outerCount + + proc k() = + t((0, 0), c(0)) + + k() + doAssert innerCount == 2 + doAssert outerCount == -2 + +block: # issue #24338 with object + type Foo = object + x, y: int + var innerCount = 0 + var outerCount = 0 + template c(w: int): int = + let q = w + inc innerCount + 0 + + template t(r: Foo; x: int) = + for _ in r.fields: + let w = x + doAssert w == 0 + dec outerCount + + proc k() = + t(Foo(x: 0, y: 0), c(0)) + + k() + doAssert innerCount == 2 + doAssert outerCount == -2