Skip to content

Commit 5f40f15

Browse files
authored
Don't bail out of inference early if effects could still be refined (#48263)
We have an early out in inference that bails if the inferred return type of the method being called is `Any`. This makes sense in the absence of effects, because once the rt has hit `Any`, there is nothing new we can learn by looking at any subsequent calls. However, in the presence of effects, we likely want to keep going if we can prove all methods of the callsite `:foldable` as being `:foldable` can save significant inference time down the line if it enables concrete evaluation of the containing function.
1 parent 9582937 commit 5f40f15

File tree

3 files changed

+12
-3
lines changed

3 files changed

+12
-3
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
194194
conditionals[2][i] = tmerge(conditionals[2][i], cnd.elsetype)
195195
end
196196
end
197-
if bail_out_call(interp, rettype, sv)
197+
if bail_out_call(interp, rettype, sv, effects)
198+
add_remark!(interp, sv, "One of the matched returned maximally imprecise information. Bailing on call.")
198199
break
199200
end
200201
end
@@ -838,6 +839,7 @@ function concrete_eval_eligible(interp::AbstractInterpreter,
838839
elseif !result.effects.noinbounds && stmt_taints_inbounds_consistency(sv)
839840
# If the current statement is @inbounds or we propagate inbounds, the call's consistency
840841
# is tainted and not consteval eligible.
842+
add_remark!(interp, sv, "[constprop] Concrete evel disabled for inbounds")
841843
return nothing
842844
end
843845
isoverlayed(method_table(interp)) && !is_nonoverlayed(result.effects) && return nothing

base/compiler/inferencestate.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,8 @@ add_remark!(::AbstractInterpreter, sv::Union{InferenceState, IRCode}, remark) =
224224
function bail_out_toplevel_call(::AbstractInterpreter, @nospecialize(callsig), sv::Union{InferenceState, IRCode})
225225
return isa(sv, InferenceState) && sv.restrict_abstract_call_sites && !isdispatchtuple(callsig)
226226
end
227-
function bail_out_call(::AbstractInterpreter, @nospecialize(rt), sv::Union{InferenceState, IRCode})
228-
return rt === Any
227+
function bail_out_call(::AbstractInterpreter, @nospecialize(rt), sv::Union{InferenceState, IRCode}, effects::Effects)
228+
return rt === Any && !is_foldable(effects)
229229
end
230230
function bail_out_apply(::AbstractInterpreter, @nospecialize(rt), sv::Union{InferenceState, IRCode})
231231
return rt === Any

test/compiler/inference.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4697,3 +4697,10 @@ Base.@constprop :aggressive type_level_recurse1(x...) = x[1] == 2 ? 1 : (length(
46974697
Base.@constprop :aggressive type_level_recurse2(x...) = type_level_recurse1(x...)
46984698
type_level_recurse_entry() = Val{type_level_recurse1(1)}()
46994699
@test Base.return_types(type_level_recurse_entry, ()) |> only == Val{1}
4700+
4701+
# Test that inference doesn't give up if it can potentially refine effects,
4702+
# even if the return type is Any.
4703+
f_no_bail_effects_any(x::Any) = x
4704+
f_no_bail_effects_any(x::NamedTuple{(:x,), Tuple{Any}}) = getfield(x, 1)
4705+
g_no_bail_effects_any(x::Any) = f_no_bail_effects_any(x)
4706+
@test Core.Compiler.is_total(Base.infer_effects(g_no_bail_effects_any, Tuple{Any}))

0 commit comments

Comments
 (0)