diff --git a/bin/generate_builtins.jl b/bin/generate_builtins.jl index b638cbd0..d76ea7b6 100644 --- a/bin/generate_builtins.jl +++ b/bin/generate_builtins.jl @@ -132,10 +132,15 @@ function maybe_evaluate_builtin(frame, call_expr, expand::Bool) f = @lookup(frame, fex) end - @static if isdefined(Core, :OpaqueClosure) - if f isa Core.OpaqueClosure - return Some{Any}(f(args...)) + if @static isdefined(Core, :OpaqueClosure) && f isa Core.OpaqueClosure + if expand + if !Core.Compiler.uncompressed_ir(f.source).inferred + return Expr(:call, f, args[2:end]...) + else + @debug "not interpreting opaque closure \$f since it contains inferred code" + end end + return Some{Any}(f(args...)) end if !(isa(f, Core.Builtin) || isa(f, Core.IntrinsicFunction)) return call_expr diff --git a/src/builtins.jl b/src/builtins.jl index 846bcc32..40d7b37a 100644 --- a/src/builtins.jl +++ b/src/builtins.jl @@ -38,10 +38,15 @@ function maybe_evaluate_builtin(frame, call_expr, expand::Bool) f = @lookup(frame, fex) end - @static if isdefined(Core, :OpaqueClosure) - if f isa Core.OpaqueClosure - return Some{Any}(f(args...)) + if @static isdefined(Core, :OpaqueClosure) && f isa Core.OpaqueClosure + if expand + if !Core.Compiler.uncompressed_ir(f.source).inferred + return Expr(:call, f, args[2:end]...) + else + @debug "not interpreting opaque closure $f since it contains inferred code" + end end + return Some{Any}(f(args...)) end if !(isa(f, Core.Builtin) || isa(f, Core.IntrinsicFunction)) return call_expr diff --git a/src/construct.jl b/src/construct.jl index cd565933..64e54971 100644 --- a/src/construct.jl +++ b/src/construct.jl @@ -241,7 +241,16 @@ function prepare_call(@nospecialize(f), allargs; enter_generated = false) end argtypesv = Any[_Typeof(a) for a in allargs] argtypes = Tuple{argtypesv...} - method = whichtt(argtypes) + if @static isdefined(Core, :OpaqueClosure) && f isa Core.OpaqueClosure + method = f.source + # don't try to interpret optimized ir + if Core.Compiler.uncompressed_ir(method).inferred + @debug "not interpreting opaque closure $f since it contains inferred code" + return nothing + end + else + method = whichtt(argtypes) + end if method === nothing # Call it to generate the exact error return f(allargs[2:end]...) @@ -298,7 +307,10 @@ function prepare_framedata(framecode, argvals::Vector{Any}, lenv::SimpleVector=e nargs, meth_nargs = length(argvals), Int(meth.nargs) islastva = meth.isva && nargs >= meth_nargs for i = 1:meth_nargs-islastva - if nargs >= i + # for OCs #self# actually refers to the captures instead + if @static isdefined(Core, :OpaqueClosure) && i == 1 && (oc = argvals[1]) isa Core.OpaqueClosure + locals[i], last_reference[i] = Some{Any}(oc.captures), 1 + elseif i <= nargs locals[i], last_reference[i] = Some{Any}(argvals[i]), 1 else locals[i] = Some{Any}(()) diff --git a/test/interpret.jl b/test/interpret.jl index 34ad17fe..131d2676 100644 --- a/test/interpret.jl +++ b/test/interpret.jl @@ -944,7 +944,16 @@ end @test @interpret foo_536(UInt8('A')) @static if isdefined(Base.Experimental, Symbol("@opaque")) - @test @interpret (Base.Experimental.@opaque x->3*x)(4) == 12 + @testset "opaque closures" begin + g(x) = 3x + f = Base.Experimental.@opaque x -> g(x) + @test @interpret f(4) == 12 + + # test stepping into opaque closures + @breakpoint g(1) + fr = JuliaInterpreter.enter_call_expr(Expr(:call, f, 4)) + @test JuliaInterpreter.finish_and_return!(fr) isa JuliaInterpreter.BreakpointRef + end end # CassetteOverlay, issue #552