diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 2131a11e40ef3..c0956b2c820ef 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -204,6 +204,11 @@ function abstract_call_method_with_const_args(@nospecialize(rettype), @nospecial return result end +struct EdgeCycleLimited + newsig + sig +end + function abstract_call_method(method::Method, @nospecialize(sig), sparams::SimpleVector, sv::InferenceState) if method.name === :depwarn && isdefined(Main, :Base) && method.module === Main.Base return Any, false, nothing @@ -301,6 +306,10 @@ function abstract_call_method(method::Method, @nospecialize(sig), sparams::Simpl newsig = limit_type_size(sig, comparison, sv.linfo.specTypes, sv.params.TUPLE_COMPLEXITY_LIMIT_DEPTH, spec_len) if newsig !== sig + if edgecycle && sv.params.trace_inference_limits + push!(sv.params.trace_buffer, EdgeCycleLimited(newsig, sig)) + end + # continue inference, but note that we've limited parameter complexity # on this call (to ensure convergence), so that we don't cache this result if call_result_unused(sv) diff --git a/base/compiler/params.jl b/base/compiler/params.jl index 91b9ee35ee9b6..86214819ec395 100644 --- a/base/compiler/params.jl +++ b/base/compiler/params.jl @@ -34,6 +34,10 @@ struct Params # contains more than this many elements MAX_TUPLE_SPLAT::Int + # Whether to trace when inference decides to truncate inference + trace_inference_limits::Bool + trace_buffer::Vector{Any} + # reasonable defaults global function CustomParams(world::UInt, ; @@ -47,13 +51,14 @@ struct Params tupletype_depth::Int = DEFAULT_PARAMS.TUPLE_COMPLEXITY_LIMIT_DEPTH, tuple_splat::Int = DEFAULT_PARAMS.MAX_TUPLE_SPLAT, union_splitting::Int = DEFAULT_PARAMS.MAX_UNION_SPLITTING, - apply_union_enum::Int = DEFAULT_PARAMS.MAX_APPLY_UNION_ENUM) + apply_union_enum::Int = DEFAULT_PARAMS.MAX_APPLY_UNION_ENUM, + trace_inference_limits::Bool = false) return new(Vector{InferenceResult}(), world, false, inlining, ipo_constant_propagation, aggressive_constant_propagation, inline_cost_threshold, inline_nonleaf_penalty, inline_tupleret_bonus, max_methods, union_splitting, apply_union_enum, tupletype_depth, - tuple_splat) + tuple_splat, trace_inference_limits, Any[]) end function Params(world::UInt) inlining = inlining_enabled() @@ -64,7 +69,7 @@ struct Params #=inline_tupleret_bonus, max_methods, union_splitting, apply_union_enum=# 400, 4, 4, 8, #=tupletype_depth, tuple_splat=# - 3, 32) + 3, 32, false, Any[]) end end const DEFAULT_PARAMS = Params(UInt(0)) diff --git a/base/reflection.jl b/base/reflection.jl index f366c467451ce..eeb57bb1ff2c7 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -962,7 +962,8 @@ possible options are `:source` or `:none`. function code_typed(@nospecialize(f), @nospecialize(types=Tuple); optimize=true, debuginfo::Symbol=:default, world = ccall(:jl_get_world_counter, UInt, ()), - params = Core.Compiler.Params(world)) + trace = false, + params = Core.Compiler.CustomParams(world; trace_inference_limits=trace)) 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")) @@ -984,6 +985,11 @@ function code_typed(@nospecialize(f), @nospecialize(types=Tuple); debuginfo == :none && remove_linenums!(code) push!(asts, code => ty) end + if trace && !isempty(params.trace_buffer) + for entry in params.trace_buffer + @info entry + end + end return asts end diff --git a/base/show.jl b/base/show.jl index 410a48137e016..16ea551c5269b 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1614,6 +1614,15 @@ function show(io::IO, src::CodeInfo; debuginfo::Symbol=:source) print(io, ")") end +# Show for inference limit trace objects +function show(io::IO, ecl::Core.Compiler.EdgeCycleLimited) + print(io, "Signature ") + show_tuple_as_call(io, Symbol(""), ecl.sig) + print(io, " was narrowed to ") + show_tuple_as_call(io, Symbol(""), ecl.newsig) + println(io, " due to recursion [EdgeCycleLimited]") +end + function dump(io::IOContext, x::SimpleVector, n::Int, indent) if isempty(x)