Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions compiler/ast2nif.nim
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ type
#writtenTypes: seq[PType] # types written in this module, to be unloaded later
#writtenSyms: seq[PSym] # symbols written in this module, to be unloaded later
writtenPackages: HashSet[string]
inBlock: int # inc when entering a block expression/statement

const
# Symbol kinds that are always local to a proc and should never have module suffix
Expand Down Expand Up @@ -433,7 +434,7 @@ template withNode(w: var Writer; dest: var TokenBuf; n: PNode; body: untyped) =

proc addLocalSym(w: var Writer; n: PNode) =
## Add symbol from a node to locals set if it's a symbol node
if n != nil and n.kind == nkSym and n.sym != nil and w.inProc > 0:
if n != nil and n.kind == nkSym and n.sym != nil and (w.inProc > 0 or w.inBlock > 0):
w.locals.incl(n.sym.itemId)

proc addLocalSyms(w: var Writer; n: PNode) =
Expand Down Expand Up @@ -578,14 +579,18 @@ proc writeNode(w: var Writer; dest: var TokenBuf; n: PNode; forAst = false) =
of nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef, nkMacroDef, nkTemplateDef:
# For top-level named routines (not forAst), just write the symbol.
# The full AST will be stored in the symbol's sdef.
if not forAst and n[namePos].kind == nkSym:
if not forAst and n[namePos].kind == nkSym and w.inBlock == 0:
writeSym(w, dest, n[namePos].sym)
else:
# Writing AST inside sdef or anonymous proc: write full structure
# Writing AST inside sdef, anonymous proc or block statement: write full structure
inc w.inProc
var ast = n
var skipParams = false
if n[namePos].kind == nkSym:
if not forAst and w.inBlock > 0:
# routines under block expressions/statements not inside routines are local
# and top level routines cannot call them.
w.locals.incl(n[namePos].sym.itemId)
ast = n[namePos].sym.astImpl
if ast == nil: ast = n
else: skipParams = true
Expand Down Expand Up @@ -618,6 +623,12 @@ proc writeNode(w: var Writer; dest: var TokenBuf; n: PNode; forAst = false) =
# Note: nkExportExceptStmt is transformed to nkExportStmt by semExportExcept,
# but we handle both just in case
trExport w, n
of nkBlockExpr, nkBlockStmt:
inc w.inBlock
w.withNode dest, n:
for i in 0 ..< n.len:
writeNode(w, dest, n[i], forAst)
dec w.inBlock
else:
w.withNode dest, n:
for i in 0 ..< n.len:
Expand Down Expand Up @@ -1371,6 +1382,14 @@ proc loadNode(c: var DecodeContext; n: var Cursor; thisModule: string;
of nkNilLit:
c.withNode n, result, kind:
discard
of nkBlockExpr, nkBlockStmt:
var scanCursor = n
# Fully load local symbols defined under block expressions/statements outside of routines
# as they are not lazy loaded like global symbols.
c.extractLocalSymsFromTree(scanCursor, thisModule, localSyms)
c.withNode n, result, kind:
while n.kind != ParRi:
result.sons.add c.loadNode(n, thisModule, localSyms)
else:
c.withNode n, result, kind:
while n.kind != ParRi:
Expand Down
5 changes: 5 additions & 0 deletions tests/ic/mmacros.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
macro exportedMacro*(x: untyped): untyped = x
macro exportedMacroWithBlock*(x: untyped): untyped =
block:
let y = x
y
62 changes: 62 additions & 0 deletions tests/ic/tblocks.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# tests procs, templates and variables under block statements/expressions

block:
proc foo(x: int): int {.compileTime.} = x + 10

const X = foo(1)
assert X == 11

proc bar(x: int): int {.compileTime.} = foo(x) + X

const Y = bar(100)
assert Y == 121

const Z = block:
var a = Y
foo(a)
assert Z == 131

const Test0 = block:
proc foo(x: int): int {.compileTime.} = x + 1
var x = foo(123)
x
assert Test0 == 124

block:
proc foo(x: int): int = x + 10

let x0 = foo(1)
assert x0 == 11

proc bar(x: int): int = foo(x)

let x1 = bar(100)
assert x1 == 110

let x2 = block:
var a = x1
foo(a)
assert x2 == 120

let test1 = block:
proc foo(x: int): int = x + 7
var x = foo(100)
x
assert test1 == 107

block:
template foo(x: untyped): untyped = x

var x = 11
foo:
x += 100
assert x == 111

template bar(x: untyped): untyped =
x
foo(x)

var y = 22
bar:
y += 1000
assert y == 2022
20 changes: 20 additions & 0 deletions tests/ic/tblocks_macros.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# test macros without import
macro test0(x: untyped): untyped = x

block:
var x = 0
test0:
x = 123
assert x == 123

# issue # 25610
block:
macro foo(u: untyped): untyped =
discard

macro bar(x: untyped): untyped = x

bar:
let x = 111

assert x == 111
15 changes: 15 additions & 0 deletions tests/ic/tblocks_macros_import.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# test imported macros
import mmacros

exportedMacro:
const Test0 = 777
assert Test0 == 777

block:
exportedMacro:
let x = 123
assert x == 123

exportedMacroWithBlock:
const Test1 = 321
assert Test1 == 321
Loading