diff --git a/src/JuliaInterpreter.jl b/src/JuliaInterpreter.jl index ac9e94290108b..cb28a6081333b 100644 --- a/src/JuliaInterpreter.jl +++ b/src/JuliaInterpreter.jl @@ -358,10 +358,12 @@ function determine_method_for_expr(expr; enter_generated = false) end f, allargs = prepare_args(f, allargs, kwargs.args) # Can happen for thunks created by generated functions - if !isa(f, Core.Builtin) && !isa(f, Core.IntrinsicFunction) - return prepare_call(f, allargs; enter_generated=enter_generated) + if isa(f, Core.Builtin) || isa(f, Core.IntrinsicFunction) + return nothing + elseif f === getproperty && allargs[2] <: Vararg + return nothing # https://github.com/JuliaLang/julia/issues/30995 end - nothing + return prepare_call(f, allargs; enter_generated=enter_generated) end function get_source(meth) @@ -779,6 +781,8 @@ function extract_args(__module__, ex0) Expr(:call, NamedTuple{names,typeof(values)}, values), map(x->isexpr(x, :parameters) ? QuoteNode(x) : x, filter(x->!isexpr(x, :kw),ex0.args))...) + elseif ex0.head == :. + return Expr(:tuple, :getproperty, ex0.args...) else return Expr(:tuple, map(x->isexpr(x,:parameters) ? QuoteNode(x) : x, ex0.args)...) @@ -858,6 +862,9 @@ macro interpret(arg) theargs = $(esc(args)) stack = JuliaStackFrame[] frame = JuliaInterpreter.enter_call_expr(Expr(:call,theargs...)) + if frame === nothing + return eval(Expr(:call, map(QuoteNode, theargs)...)) + end empty!(framedict) # start fresh each time; kind of like bumping the world age at the REPL prompt empty!(genframedict) finish_and_return!(stack, frame) diff --git a/src/interpret.jl b/src/interpret.jl index 370a8e9e0b745..e798b50c48173 100644 --- a/src/interpret.jl +++ b/src/interpret.jl @@ -454,11 +454,14 @@ end finish!(stack, frame, istoplevel::Bool) = finish!(stack, frame, frame.pc[], istoplevel) """ - ret = finish_and_return!(stack, frame, pc=frame.pc[]) + ret = finish_and_return!(stack, frame, istoplevel::Bool=false) + ret = finish_and_return!(stack, frame, pc, istoplevel::Bool) Run `frame` until execution terminates, and pass back the computed return value. `stack` controls call evaluation; `stack = Compiled()` evaluates :call expressions by normal dispatch, whereas a vector of `JuliaStackFrame`s will use recursive interpretation. + +Optionally supply the starting `pc`, if you don't want to start at the current location in `frame`. """ function finish_and_return!(stack, frame, pc::JuliaProgramCounter=frame.pc[], istoplevel::Bool=false) pc = finish!(stack, frame, pc, istoplevel) diff --git a/src/localmethtable.jl b/src/localmethtable.jl index 13f98ef0118a2..f61f376d8b427 100644 --- a/src/localmethtable.jl +++ b/src/localmethtable.jl @@ -52,6 +52,9 @@ function get_call_framecode(fargs, parentframe::JuliaFrameCode, idx::Int) # See TODO in optimize! return f(fargs[2:end]...), nothing # for code that has a direct call to a builtin end + if f === getproperty && isa(fargs[2], Type) && fargs[2] <: Vararg # https://github.com/JuliaLang/julia/issues/30995 + return getproperty(fargs[2:end]...), nothing + end # HACK: don't recurse into inference. Inference sometimes returns SSAValue objects and this # seems to confuse lookup_var. if f === Base._return_type diff --git a/test/interpret.jl b/test/interpret.jl index 0790daa409db7..9a845e6f075b1 100644 --- a/test/interpret.jl +++ b/test/interpret.jl @@ -33,3 +33,8 @@ fkw(x::Int8; y=0, z="hello") = y # issue #3 @test @interpret(joinpath("/home/julia/base", "sysimg.jl")) == "/home/julia/base/sysimg.jl" @test @interpret(10.0^4) == 10.0^4 +# issue #6 +@test @interpret(Array.body.body.name) === Array.body.body.name +@test @interpret(Vararg.body.body.name) === Vararg.body.body.name +frame = JuliaInterpreter.prepare_toplevel(Main, :(Vararg.body.body.name)) +@test JuliaInterpreter.finish_and_return!(JuliaStackFrame[], frame, true) === Vararg.body.body.name