Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Warn if @code_typed, @code_warntype, etc. are showing inaccurate specialization #33142

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ function signature_type(@nospecialize(f), @nospecialize(args))
end

"""
code_lowered(f, types; generated=true, debuginfo=:default)
code_lowered(f, types; generated=true, debuginfo=:default, warn_about_lying=true)

Return an array of the lowered forms (IR) for the methods matching the given generic function
and type signature.
Expand All @@ -789,7 +789,7 @@ The keyword debuginfo controls the amount of code metadata present in the output
Note that an error will be thrown if `types` are not leaf types when `generated` is
`true` and any of the corresponding methods are an `@generated` method.
"""
function code_lowered(@nospecialize(f), @nospecialize(t=Tuple); generated::Bool=true, debuginfo::Symbol=:default)
function code_lowered(@nospecialize(f), @nospecialize(t=Tuple); generated::Bool=true, debuginfo::Symbol=:default, warn_about_lying::Bool=true)
if @isdefined(IRShow)
debuginfo = IRShow.debuginfo(debuginfo)
elseif debuginfo == :default
Expand All @@ -799,6 +799,12 @@ function code_lowered(@nospecialize(f), @nospecialize(t=Tuple); generated::Bool=
throw(ArgumentError("'debuginfo' must be either :source or :none"))
end
return map(method_instances(f, t)) do m
if warn_about_lying
isa_compileable_sig = ccall(:jl_isa_compileable_sig, Cint, (Any, Any), m.specTypes, m.def) != 0
if !isa_compileable_sig
println("WARNING: I am lying to you.")
end
end
if generated && isgenerated(m)
if may_invoke_generator(m)
return ccall(:jl_code_for_staged, Any, (Any,), m)::CodeInfo
Expand Down Expand Up @@ -1060,7 +1066,7 @@ end


"""
code_typed(f, types; optimize=true, debuginfo=:default)
code_typed(f, types; optimize=true, debuginfo=:default, warn_about_lying=true)

Returns an array of type-inferred lowered form (IR) for the methods matching the given
generic function and type signature. The keyword argument `optimize` controls whether
Expand All @@ -1072,7 +1078,8 @@ function code_typed(@nospecialize(f), @nospecialize(types=Tuple);
optimize=true,
debuginfo::Symbol=:default,
world = get_world_counter(),
params = Core.Compiler.Params(world))
params = Core.Compiler.Params(world),
warn_about_lying::Bool=true)
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 All @@ -1089,6 +1096,13 @@ function code_typed(@nospecialize(f), @nospecialize(types=Tuple);
asts = []
for x in _methods(f, types, -1, world)
meth = func_for_method_checked(x[3], types, x[2])
if warn_about_lying
mi = Core.Compiler.specialize_method(meth, x[1], x[2])::MethodInstance
isa_compileable_sig = ccall(:jl_isa_compileable_sig, Cint, (Any, Any), mi.specTypes, mi.def) != 0
if !isa_compileable_sig
println("WARNING: I am lying to you.")
end
end
(code, ty) = Core.Compiler.typeinf_code(meth, x[1], x[2], optimize, params)
code === nothing && error("inference not successful") # inference disabled?
debuginfo == :none && remove_linenums!(code)
Expand Down
2 changes: 1 addition & 1 deletion src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ static jl_value_t *ml_matches(jl_typemap_t *ml, int offs,
size_t world, size_t *min_valid, size_t *max_valid);

// get the compilation signature specialization for this method
static void jl_compilation_sig(
JL_DLLEXPORT void jl_compilation_sig(
jl_tupletype_t *const tt, // the original tupletype of the call : this is expected to be a relative simple type (no Varags, Union, UnionAll, etc.)
jl_svec_t *sparams,
jl_method_t *definition,
Expand Down
6 changes: 3 additions & 3 deletions stdlib/InteractiveUtils/src/codeview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function warntype_type_printer(io::IO, @nospecialize(ty), used::Bool)
end

"""
code_warntype([io::IO], f, types; debuginfo=:default)
code_warntype([io::IO], f, types; debuginfo=:default, optimize=false, warn_about_lying=true)

Prints lowered and type-inferred ASTs for the methods matching the given generic function
and type signature to `io` which defaults to `stdout`. The ASTs are annotated in such a way
Expand All @@ -31,10 +31,10 @@ 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); debuginfo::Symbol=:default, optimize::Bool=false)
function code_warntype(io::IO, @nospecialize(f), @nospecialize(t); debuginfo::Symbol=:default, optimize::Bool=false, warn_about_lying::Bool=true)
debuginfo = Base.IRShow.debuginfo(debuginfo)
lineprinter = Base.IRShow.__debuginfo[debuginfo]
for (src, rettype) in code_typed(f, t, optimize=optimize)
for (src, rettype) in code_typed(f, t; debuginfo=debuginfo, optimize=optimize, warn_about_lying=warn_about_lying)
lambda_io::IOContext = io
if src.slotnames !== nothing
slotnames = Base.sourceinfo_slotnames(src)
Expand Down