Skip to content

Commit 77a997b

Browse files
authored
Don't split scope-modifying blocks (#431)
Fixes #427
1 parent 30c7650 commit 77a997b

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

src/construct.jl

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -437,11 +437,8 @@ mutable struct ExprSplitter
437437
lnn::Union{LineNumberNode,Nothing}
438438
end
439439
function ExprSplitter(mod::Module, ex::Expr; lnn=nothing)
440-
index = Int[]
441-
if ex.head === :block || ex.head === :toplevel
442-
push!(index, 1)
443-
end
444-
iter = ExprSplitter([(mod,ex)], index, lnn)
440+
iter = ExprSplitter(Tuple{Module,Expr}[], Int[], lnn)
441+
push_modex!(iter, mod, ex)
445442
queuenext!(iter)
446443
return iter
447444
end
@@ -452,7 +449,15 @@ Base.eltype(::Type{ExprSplitter}) = Tuple{Module,Expr}
452449
function push_modex!(iter::ExprSplitter, mod::Module, ex::Expr)
453450
push!(iter.stack, (mod, ex))
454451
if ex.head === :toplevel || ex.head === :block
455-
push!(iter.index, 1)
452+
# Issue #427
453+
modifies_scope = false
454+
for a in ex.args
455+
if isa(a, Expr) && a.head (:local, :global)
456+
modifies_scope = true
457+
break
458+
end
459+
end
460+
push!(iter.index, modifies_scope ? 0 : 1)
456461
end
457462
return iter
458463
end
@@ -504,6 +509,10 @@ function queuenext!(iter::ExprSplitter)
504509
elseif head === :block || head === :toplevel
505510
# Container expression
506511
idx = iter.index[end]
512+
if idx == 0
513+
# return the whole block (issue #427)
514+
return nothing
515+
end
507516
while idx <= length(ex.args)
508517
a = ex.args[idx]
509518
if isa(a, LineNumberNode)
@@ -538,6 +547,15 @@ function Base.iterate(iter::ExprSplitter, state=nothing)
538547
push_modex!(iter, mod, body)
539548
end
540549
end
550+
if ex.head === :block || ex.head === :toplevel
551+
# This was a block that we couldn't safely descend into (issue #427)
552+
if !isempty(iter.index) && iter.index[end] > length(iter.stack[end][2].args)
553+
pop!(iter.stack)
554+
pop!(iter.index)
555+
queuenext!(iter)
556+
end
557+
return (mod, ex), nothing
558+
end
541559
queuenext!(iter)
542560
# :global expressions can't be lowered. For debugging it might be nice
543561
# to still return the lnn, but then we have to work harder on detecting them.

test/toplevel.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,3 +480,37 @@ end
480480
frame = Frame(ToplevelParameters, ex)
481481
@test JuliaInterpreter.finish!(frame, true) === nothing
482482
end
483+
484+
@testset "Issue #427" begin
485+
ex = :(begin
486+
local foo = 10
487+
sin(foo)
488+
end)
489+
for (mod, ex) in ExprSplitter(@__MODULE__, ex)
490+
@test JuliaInterpreter.finish!(Frame(mod, ex), true) === nothing
491+
end
492+
@test length(collect(ExprSplitter(@__MODULE__, ex))) == 1
493+
ex = :(begin
494+
3 + 7
495+
module Local
496+
local foo = 10
497+
sin(foo)
498+
end
499+
end)
500+
modexs = collect(ExprSplitter(@__MODULE__, ex))
501+
@test length(modexs) == 2
502+
@test modexs[2][1] == getfield(@__MODULE__, :Local)
503+
for (mod, ex) in modexs
504+
@test JuliaInterpreter.finish!(Frame(mod, ex), true) === nothing
505+
end
506+
ex = :(begin
507+
3 + 7
508+
module Local
509+
local foo = 10
510+
sin(foo)
511+
end
512+
3 + 7
513+
end)
514+
modexs = collect(ExprSplitter(@__MODULE__, ex))
515+
@test length(modexs) == 3
516+
end

0 commit comments

Comments
 (0)