Skip to content

Commit 8043dbc

Browse files
authored
add support for preset current_scope (#619)
* add support for preset `current_scope` There are cases where we invoke JuliaInterpreter from a context with some scope is set (e.g. `@test_logs (...) (@InterPret ...)`). * fix `@test_logs` test case
1 parent 55e33d0 commit 8043dbc

File tree

7 files changed

+79
-44
lines changed

7 files changed

+79
-44
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
version:
1717
- '1.6' # LTS
1818
- '1' # current stable
19+
- '1.11-nightly' # next stable
1920
- 'nightly'
2021
os:
2122
- ubuntu-latest

bin/generate_builtins.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,11 @@ function maybe_evaluate_builtin(frame, call_expr, expand::Bool)
218218
"""
219219
elseif @static isdefined(Core, :current_scope) && f === Core.current_scope
220220
if nargs == 0
221-
if isempty(frame.framedata.current_scopes)
222-
return Some{Any}(nothing)
223-
else
224-
return Some{Any}(frame.framedata.current_scopes[end])
221+
currscope = Core.current_scope()
222+
for scope in frame.framedata.current_scopes
223+
currscope = Scope(currscope, scope.values...)
225224
end
225+
return Some{Any}(currscope)
226226
else
227227
return Some{Any}(Core.current_scope(getargs(args, frame)...))
228228
end

src/builtins.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,11 @@ function maybe_evaluate_builtin(frame, call_expr, expand::Bool)
126126
end
127127
elseif @static isdefined(Core, :current_scope) && f === Core.current_scope
128128
if nargs == 0
129-
if isempty(frame.framedata.current_scopes)
130-
return Some{Any}(nothing)
131-
else
132-
return Some{Any}(frame.framedata.current_scopes[end])
129+
currscope = Core.current_scope()
130+
for scope in frame.framedata.current_scopes
131+
currscope = Scope(currscope, scope.values...)
133132
end
133+
return Some{Any}(currscope)
134134
else
135135
return Some{Any}(Core.current_scope(getargs(args, frame)...))
136136
end

src/construct.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ function prepare_framedata(framecode, argvals::Vector{Any}, lenv::SimpleVector=e
287287
ssavalues = Vector{Any}(undef, ng)
288288
sparams = Vector{Any}(undef, 0)
289289
exception_frames = Int[]
290-
current_scopes = Any[]
290+
current_scopes = Scope[]
291291
last_reference = Vector{Int}(undef, ns)
292292
callargs = Any[]
293293
last_exception = Ref{Any}(_INACTIVE_EXCEPTION.instance)

src/interpret.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,13 +224,15 @@ end
224224

225225
function native_call(fargs::Vector{Any}, frame::Frame)
226226
f = popfirst!(fargs) # now it's really just `args`
227-
if (@static isdefined(Core.IR, :EnterNode) && true) && !isempty(frame.framedata.current_scopes)
227+
if (@static isdefined(Core.IR, :EnterNode) && true)
228228
newscope = Core.current_scope()
229-
for scope in frame.framedata.current_scopes
230-
newscope = Scope(newscope, scope.values...)
229+
if newscope !== nothing || !isempty(frame.framedata.current_scopes)
230+
for scope in frame.framedata.current_scopes
231+
newscope = Scope(newscope, scope.values...)
232+
end
233+
ex = Expr(:tryfinally, :($f($fargs...)), nothing, newscope)
234+
return Core.eval(moduleof(frame), ex)
231235
end
232-
ex = Expr(:tryfinally, :($f($fargs...)), nothing, newscope)
233-
return Core.eval(moduleof(frame), ex)
234236
end
235237
return Base.invokelatest(f, fargs...)
236238
end

test/interpret.jl

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -742,11 +742,12 @@ end
742742
@test @interpret(f(D)) === f(D)
743743

744744
# issue #441 & #535
745-
flog() = @info "logging macros"
746-
@test_logs (:info, "logging macros") @test @interpret flog() === nothing
747-
flog2() = @error "this error is ok"
748-
frame = JuliaInterpreter.enter_call(flog2)
749-
@test_logs (:error, "this error is ok") @test debug_command(frame, :c) === nothing
745+
f_log1() = @info "logging macros"
746+
@test (@test_logs (:info, "logging macros") (@interpret f_log1())) === nothing
747+
f_log2() = @error "this error is ok"
748+
let frame = JuliaInterpreter.enter_call(f_log2)
749+
@test (@test_logs (:error, "this error is ok") debug_command(frame, :c)) === nothing
750+
end
750751
end
751752

752753
struct A396
@@ -998,29 +999,5 @@ func_arrayref(a, i) = Core.arrayref(true, a, i)
998999
@test 2 == @interpret func_arrayref([1,2,3], 2)
9991000

10001001
@static if isdefined(Base, :ScopedValues)
1001-
const sval = ScopedValue(1)
1002-
@test 1 == @interpret getindex(sval)
1003-
1004-
# current_scope support for interpretation
1005-
sval_func1() = @with sval => 2 begin
1006-
return sval[]
1007-
end
1008-
@test 2 == @interpret sval_func1()
1009-
1010-
# current_scope support for compiled calls
1011-
_sval_func2() = sval[]
1012-
sval_func2() = @with sval => 2 begin
1013-
return _sval_func2()
1014-
end
1015-
let m = only(methods(_sval_func2))
1016-
push!(JuliaInterpreter.compiled_methods, m)
1017-
try
1018-
@test 2 == @interpret sval_func2()
1019-
finally
1020-
delete!(JuliaInterpreter.compiled_methods, m)
1021-
end
1022-
end
1023-
let frame = JuliaInterpreter.enter_call(sval_func2)
1024-
@test 2 == JuliaInterpreter.finish_and_return!(Compiled(), frame)
1025-
end
1002+
@testset "interpret_scopedvalues.jl" include("interpret_scopedvalues.jl")
10261003
end

test/interpret_scopedvalues.jl

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
module interpret_scopedvalues
2+
3+
using Test, JuliaInterpreter
4+
using Base.ScopedValues
5+
6+
const sval1 = ScopedValue(1)
7+
const sval2 = ScopedValue(1)
8+
@test 1 == @interpret getindex(sval1)
9+
10+
# current_scope support for interpretation
11+
sval1_func1() = @with sval1 => 2 begin
12+
return sval1[]
13+
end
14+
@test 2 == @interpret sval1_func1()
15+
sval12_func1() = @with sval1 => 2 begin
16+
@with sval2 => 3 begin
17+
return sval1[], sval2[]
18+
end
19+
end
20+
@test (2, 3) == @interpret sval12_func1()
21+
22+
# current_scope support for compiled calls
23+
_sval1_func2() = sval1[]
24+
sval1_func2() = @with sval1 => 2 begin
25+
return _sval1_func2()
26+
end
27+
let m = only(methods(_sval1_func2))
28+
push!(JuliaInterpreter.compiled_methods, m)
29+
try
30+
@test 2 == @interpret sval1_func2()
31+
finally
32+
delete!(JuliaInterpreter.compiled_methods, m)
33+
end
34+
end
35+
let frame = JuliaInterpreter.enter_call(sval1_func2)
36+
@test 2 == JuliaInterpreter.finish_and_return!(Compiled(), frame)
37+
end
38+
39+
# preset `current_scope` support
40+
@test 2 == @with sval1 => 2 begin
41+
@interpret getindex(sval1)
42+
end
43+
@test (2, 3) == @with sval1 => 2 sval2 => 3 begin
44+
@interpret(getindex(sval1)), @interpret(getindex(sval2))
45+
end
46+
@test (2, 3) == @with sval1 => 2 begin @with sval2 => 3 begin
47+
@interpret(getindex(sval1)), @interpret(getindex(sval2))
48+
end end
49+
let frame = JuliaInterpreter.enter_call() do
50+
sval1[], sval2[]
51+
end
52+
@test (2, 3) == @with sval1 => 2 sval2 => 3 JuliaInterpreter.finish_and_return!(frame)
53+
end
54+
55+
end # module interpret_scopedvalues

0 commit comments

Comments
 (0)