Skip to content

Commit

Permalink
InteractiveUtils: make default argtype of code_llvm etc. work with …
Browse files Browse the repository at this point in the history
…functions with single method (JuliaLang#42496)

`code_llvm` and `code_native` expects a single matching method, but the
default value of `types=Tuple` argument doesn't match with any function 
signature and so we actually can't use that default value.

With this PR, the default argument type will be computed by `default_tt`,
which returns an appropriate signature if a function only has a single 
method, otherwise returns `Tuple` (which is the same default value as before).

Now `code_llvm` and `code_native` by default work with functions that 
have a single method, e.g.:
```julia
code_llvm() do # previously, we need to call `code_llvm(()) do ... end`
    sin(42)
end
```
  • Loading branch information
aviatesk authored and LilithHafner committed Mar 8, 2022
1 parent 09d57e3 commit 519e31e
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 10 deletions.
18 changes: 15 additions & 3 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,7 @@ additional optimizations, such as inlining, are also applied.
The keyword `debuginfo` controls the amount of code metadata present in the output,
possible options are `:source` or `:none`.
"""
function code_typed(@nospecialize(f), @nospecialize(types=Tuple);
function code_typed(@nospecialize(f), @nospecialize(types=default_tt(f));
optimize=true,
debuginfo::Symbol=:default,
world = get_world_counter(),
Expand All @@ -1181,6 +1181,18 @@ function code_typed(@nospecialize(f), @nospecialize(types=Tuple);
return code_typed_by_type(tt; optimize, debuginfo, world, interp)
end

# returns argument tuple type which is supposed to be used for `code_typed` and its family;
# if there is a single method this functions returns the method argument signature,
# otherwise returns `Tuple` that doesn't match with any signature
function default_tt(@nospecialize(f))
ms = methods(f)
if length(ms) == 1
return tuple_type_tail(only(ms).sig)
else
return Tuple
end
end

"""
code_typed_by_type(types::Type{<:Tuple}; ...)
Expand Down Expand Up @@ -1218,7 +1230,7 @@ function code_typed_by_type(@nospecialize(tt::Type);
return asts
end

function code_typed_opaque_closure(@nospecialize(closure::Core.OpaqueClosure), @nospecialize(types=Tuple);
function code_typed_opaque_closure(@nospecialize(closure::Core.OpaqueClosure);
optimize=true,
debuginfo::Symbol=:default,
interp = Core.Compiler.NativeInterpreter(closure.world))
Expand All @@ -1232,7 +1244,7 @@ function code_typed_opaque_closure(@nospecialize(closure::Core.OpaqueClosure), @
end
end

function return_types(@nospecialize(f), @nospecialize(types=Tuple), interp=Core.Compiler.NativeInterpreter())
function return_types(@nospecialize(f), @nospecialize(types=default_tt(f)), interp=Core.Compiler.NativeInterpreter())
ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions")
if isa(f, Core.Builtin)
throw(ArgumentError("argument is not a generic function"))
Expand Down
13 changes: 6 additions & 7 deletions stdlib/InteractiveUtils/src/codeview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Keyword argument `debuginfo` may be one of `:source` or `:none` (default), to sp
See [`@code_warntype`](@ref man-code-warntype) for more information.
"""
function code_warntype(io::IO, @nospecialize(f), @nospecialize(t);
function code_warntype(io::IO, @nospecialize(f), @nospecialize(t=Base.default_tt(f));
debuginfo::Symbol=:default, optimize::Bool=false, kwargs...)
debuginfo = Base.IRShow.debuginfo(debuginfo)
lineprinter = Base.IRShow.__debuginfo[debuginfo]
Expand Down Expand Up @@ -134,7 +134,7 @@ function code_warntype(io::IO, @nospecialize(f), @nospecialize(t);
end
nothing
end
code_warntype(@nospecialize(f), @nospecialize(t); kwargs...) =
code_warntype(@nospecialize(f), @nospecialize(t=Base.default_tt(f)); kwargs...) =
code_warntype(stdout, f, t; kwargs...)

import Base.CodegenParams
Expand Down Expand Up @@ -224,12 +224,11 @@ function code_llvm(io::IO, @nospecialize(f), @nospecialize(types), raw::Bool,
print(io, d)
end
end
code_llvm(io::IO, @nospecialize(f), @nospecialize(types=Tuple); raw::Bool=false, dump_module::Bool=false, optimize::Bool=true, debuginfo::Symbol=:default) =
code_llvm(io::IO, @nospecialize(f), @nospecialize(types=Base.default_tt(f)); raw::Bool=false, dump_module::Bool=false, optimize::Bool=true, debuginfo::Symbol=:default) =
code_llvm(io, f, types, raw, dump_module, optimize, debuginfo)
code_llvm(@nospecialize(f), @nospecialize(types=Tuple); raw=false, dump_module=false, optimize=true, debuginfo::Symbol=:default) =
code_llvm(@nospecialize(f), @nospecialize(types=Base.default_tt(f)); raw=false, dump_module=false, optimize=true, debuginfo::Symbol=:default) =
code_llvm(stdout, f, types; raw, dump_module, optimize, debuginfo)


"""
code_native([io=stdout,], f, types; syntax=:att, debuginfo=:default, binary=false, dump_module=true)
Expand All @@ -239,7 +238,7 @@ Switch assembly syntax using `syntax` symbol parameter set to `:att` for AT&T sy
Keyword argument `debuginfo` may be one of source (default) or none, to specify the verbosity of code comments.
If `binary` is `true`, it also prints the binary machine code for each instruction precedented by an abbreviated address.
"""
function code_native(io::IO, @nospecialize(f), @nospecialize(types=Tuple);
function code_native(io::IO, @nospecialize(f), @nospecialize(types=Base.default_tt(f));
dump_module::Bool=true, syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false)
d = _dump_function(f, types, true, false, false, dump_module, syntax, true, debuginfo, binary)
if highlighting[:native] && get(io, :color, false)
Expand All @@ -248,7 +247,7 @@ function code_native(io::IO, @nospecialize(f), @nospecialize(types=Tuple);
print(io, d)
end
end
code_native(@nospecialize(f), @nospecialize(types=Tuple); dump_module::Bool=true, syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false) =
code_native(@nospecialize(f), @nospecialize(types=Base.default_tt(f)); dump_module::Bool=true, syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false) =
code_native(stdout, f, types; dump_module, syntax, debuginfo, binary)
code_native(::IO, ::Any, ::Symbol) = error("invalid code_native call") # resolve ambiguous call

Expand Down
21 changes: 21 additions & 0 deletions stdlib/InteractiveUtils/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -649,3 +649,24 @@ end
end
end
end

let # `default_tt` should work with any function with one method
@test (code_warntype(devnull, function ()
sin(42)
end); true)
@test (code_warntype(devnull, function (a::Int)
sin(a)
end); true)
@test (code_llvm(devnull, function ()
sin(42)
end); true)
@test (code_llvm(devnull, function (a::Int)
sin(a)
end); true)
@test (code_native(devnull, function ()
sin(42)
end); true)
@test (code_native(devnull, function (a::Int)
sin(a)
end); true)
end
13 changes: 13 additions & 0 deletions test/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -952,3 +952,16 @@ end
@test only(code_typed(mod.foo, (); world=world1)).second == Int
@test only(code_typed(mod.foo, (); world=world2)).second == Float64
end

@testset "default_tt" begin
m = Module()
@eval m f1() = return
@test Base.default_tt(m.f1) == Tuple{}
@eval m f2(a) = return
@test Base.default_tt(m.f2) == Tuple{Any}
@eval m f3(a::Integer) = return
@test Base.default_tt(m.f3) == Tuple{Integer}
@eval m f4() = return
@eval m f4(a) = return
@test Base.default_tt(m.f4) == Tuple
end

0 comments on commit 519e31e

Please sign in to comment.