Skip to content

Commit d7d4ced

Browse files
authored
Fix revise#718 (#609)
Fixes timholy/Revise.jl#718 Also adds nested docstring test
1 parent 0089e4b commit d7d4ced

File tree

2 files changed

+54
-19
lines changed

2 files changed

+54
-19
lines changed

src/construct.jl

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,11 +338,14 @@ end
338338
"""
339339
ExprSplitter(mod::Module, ex::Expr; lnn=nothing)
340340
341-
Create an iterable that returns individual expressions together with their module of evaluation.
341+
Given a module `mod` and a top-level expression `ex` in `mod`, create an iterable that returns
342+
individual expressions together with their module of evaluation.
342343
Optionally supply an initial `LineNumberNode` `lnn`.
343344
344345
# Example
345346
347+
In a fresh session,
348+
346349
```
347350
julia> expr = quote
348351
public(x::Integer) = true
@@ -375,13 +378,13 @@ mod = Main
375378
ex = :($(Expr(:toplevel, :(#= REPL[7]:6 =#), :(const threshold = 0.1))))
376379
```
377380
378-
Note that `Main.Private` was created for you so that its internal expressions could be evaluated.
381+
`ExprSplitter` created `Main.Private` was created for you so that its internal expressions could be evaluated.
379382
`ExprSplitter` will check to see whether the module already exists and if so return it rather than
380383
try to create a new module with the same name.
381384
382385
In general each returned expression is a block with two parts: a `LineNumberNode` followed by a single expression.
383386
In some cases the returned expression may be `:toplevel`, as shown in the `const` declaration,
384-
but otherwise it will be a `:block`.
387+
but otherwise it will preserve its parent's `head` (e.g., `expr.head`).
385388
386389
# World age, frame creation, and evaluation
387390
@@ -441,7 +444,7 @@ function push_modex!(iter::ExprSplitter, mod::Module, ex::Expr)
441444
modifies_scope = false
442445
if ex.head === :block
443446
for a in ex.args
444-
if isa(a, Expr) && a.head (:local, :global)
447+
if isa(a, Expr) && a.head === :local
445448
modifies_scope = true
446449
break
447450
end

test/toplevel.jl

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,26 @@ end
2929
end
3030
end
3131
end
32-
modexs = collect(ExprSplitter(Main, ex))
33-
m, ex = first(modexs)
32+
modexs = collect(ExprSplitter(JIVisible, ex))
33+
m, ex = first(modexs) # FIXME don't use index in tests
3434
@test JuliaInterpreter.is_doc_expr(ex.args[2])
3535
Core.eval(m, ex)
3636
io = IOBuffer()
37-
show(io, @doc(Main.DocStringTest))
37+
show(io, @doc(JIVisible.DocStringTest))
3838
@test occursin("Special", String(take!(io)))
39+
40+
ex = Base.parse_input_line("""
41+
"docstring"
42+
module OuterModDocstring
43+
"docstring for InnerModDocstring"
44+
module InnerModDocstring
45+
end
46+
end
47+
""")
48+
modexs = collect(ExprSplitter(JIVisible, ex))
49+
@test isdefined(JIVisible, :OuterModDocstring)
50+
@test isdefined(JIVisible.OuterModDocstring, :InnerModDocstring)
51+
3952
# issue #538
4053
@test !JuliaInterpreter.is_doc_expr(:(Core.@doc "string"))
4154
ex = quote
@@ -44,11 +57,11 @@ end
4457
sum
4558
end
4659
modexs = collect(ExprSplitter(Main, ex))
47-
m, ex = first(modexs)
60+
m, ex = first(modexs) # FIXME don't use index in tests
4861
@test !JuliaInterpreter.is_doc_expr(ex.args[2])
4962

5063
@test !isdefined(Main, :JIInvisible)
51-
collect(ExprSplitter(JIVisible, :(module JIInvisible f() = 1 end)))
64+
collect(ExprSplitter(JIVisible, :(module JIInvisible f() = 1 end))) # this looks up JIInvisible rather than create it
5265
@test !isdefined(Main, :JIInvisible)
5366
@test isdefined(JIVisible, :JIInvisible)
5467
mktempdir() do path
@@ -71,14 +84,32 @@ end
7184
# Every package is technically parented in Main but the name may not be visible in Main
7285
@test isdefined(@__MODULE__, :TmpPkg1)
7386
@test !isdefined(@__MODULE__, :TmpPkg2)
74-
collect(ExprSplitter(Main, quote
75-
module TmpPkg2
76-
f() = 2
77-
end
78-
end))
87+
collect(ExprSplitter(@__MODULE__, quote
88+
module TmpPkg2
89+
f() = 2
90+
end
91+
end))
7992
@test isdefined(@__MODULE__, :TmpPkg1)
8093
@test !isdefined(@__MODULE__, :TmpPkg2)
8194
end
95+
96+
# Revise issue #718
97+
ex = Base.parse_input_line("""
98+
module TestPkg718
99+
100+
module TestModule718
101+
export _VARIABLE_UNASSIGNED
102+
global _VARIABLE_UNASSIGNED = -84.0
103+
end
104+
105+
using .TestModule718
106+
107+
end
108+
""")
109+
for (mod, ex) in ExprSplitter(JIVisible, ex)
110+
@test JuliaInterpreter.finish!(Frame(mod, ex), true) === nothing
111+
end
112+
@test JIVisible.TestPkg718._VARIABLE_UNASSIGNED == -84.0
82113
end
83114

84115
module Toplevel end
@@ -495,6 +526,7 @@ end
495526

496527
@testset "Recursive type definitions" begin
497528
# See https://github.com/timholy/Revise.jl/issues/417
529+
# See also the `Node` test above
498530
ex = :(struct RecursiveType x::Vector{RecursiveType} end)
499531
frame = Frame(Toplevel, ex)
500532
JuliaInterpreter.finish!(frame, true)
@@ -523,9 +555,9 @@ end
523555
sin(foo)
524556
end)
525557
for (mod, ex) in ExprSplitter(@__MODULE__, ex)
526-
@test JuliaInterpreter.finish!(Frame(mod, ex), true) === nothing
558+
@test JuliaInterpreter.finish_and_return!(Frame(mod, ex), true) == sin(10)
527559
end
528-
@test length(collect(ExprSplitter(@__MODULE__, ex))) == 1
560+
529561
ex = :(begin
530562
3 + 7
531563
module Local
@@ -534,7 +566,7 @@ end
534566
end
535567
end)
536568
modexs = collect(ExprSplitter(@__MODULE__, ex))
537-
@test length(modexs) == 2
569+
@test length(modexs) == 2 # FIXME don't use index in tests
538570
@test modexs[2][1] == getfield(@__MODULE__, :Local)
539571
for (mod, ex) in modexs
540572
@test JuliaInterpreter.finish!(Frame(mod, ex), true) === nothing
@@ -560,7 +592,7 @@ end
560592
for (mod, ex) in modexs
561593
@test JuliaInterpreter.finish!(Frame(mod, ex), true) === nothing
562594
end
563-
@test length(modexs) == 2
595+
@test length(modexs) == 2 # FIXME don't use index in tests
564596

565597
ex = Base.parse_input_line("""
566598
local foo = 10
@@ -570,5 +602,5 @@ end
570602
for (mod, ex) in modexs
571603
@test JuliaInterpreter.finish!(Frame(mod, ex), true) === nothing
572604
end
573-
@test length(modexs) == 2
605+
@test length(modexs) == 2 # FIXME don't use index in tests
574606
end

0 commit comments

Comments
 (0)