Skip to content

Commit eb9f24c

Browse files
authored
inference: ensure inferring reachable code methods (#57088)
PR #51317 was a bit over-eager about inferring inferring unreachable code methods. Filter out the Vararg case, since that can be handled by simply removing it instead of discarding the whole call. Fixes #56628
1 parent 323ca86 commit eb9f24c

File tree

5 files changed

+36
-18
lines changed

5 files changed

+36
-18
lines changed

Compiler/src/abstractinterpretation.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ function find_union_split_method_matches(interp::AbstractInterpreter, argtypes::
368368
for i in 1:length(split_argtypes)
369369
arg_n = split_argtypes[i]::Vector{Any}
370370
sig_n = argtypes_to_type(arg_n)
371+
sig_n === Bottom && continue
371372
mt = ccall(:jl_method_table_for, Any, (Any,), sig_n)
372373
mt === nothing && return FailedMethodMatch("Could not identify method table for call")
373374
mt = mt::MethodTable
@@ -614,7 +615,7 @@ function abstract_call_method(interp::AbstractInterpreter,
614615
sigtuple = unwrap_unionall(sig)
615616
sigtuple isa DataType ||
616617
return Future(MethodCallResult(Any, Any, Effects(), nothing, false, false))
617-
all(@nospecialize(x) -> valid_as_lattice(unwrapva(x), true), sigtuple.parameters) ||
618+
all(@nospecialize(x) -> isvarargtype(x) || valid_as_lattice(x, true), sigtuple.parameters) ||
618619
return Future(MethodCallResult(Union{}, Any, EFFECTS_THROWS, nothing, false, false)) # catch bad type intersections early
619620

620621
if is_nospecializeinfer(method)
@@ -2840,6 +2841,7 @@ function abstract_call_unknown(interp::AbstractInterpreter, @nospecialize(ft),
28402841
end
28412842
# non-constant function, but the number of arguments is known and the `f` is not a builtin or intrinsic
28422843
atype = argtypes_to_type(arginfo.argtypes)
2844+
atype === Bottom && return Future(CallMeta(Union{}, Union{}, EFFECTS_THROWS, NoCallInfo())) # accidentally unreachable
28432845
return abstract_call_gf_by_type(interp, nothing, arginfo, si, atype, sv, max_methods)::Future
28442846
end
28452847

Compiler/src/ssair/inlining.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,7 @@ function handle_call!(todo::Vector{Pair{Int,Any}},
13991399
cases === nothing && return nothing
14001400
cases, handled_all_cases, fully_covered, joint_effects = cases
14011401
atype = argtypes_to_type(sig.argtypes)
1402+
atype === Union{} && return nothing # accidentally actually unreachable
14021403
handle_cases!(todo, ir, idx, stmt, atype, cases, handled_all_cases, fully_covered, joint_effects)
14031404
end
14041405

Compiler/src/tfuncs.jl

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3016,24 +3016,28 @@ function abstract_applicable(interp::AbstractInterpreter, argtypes::Vector{Any},
30163016
isvarargtype(argtypes[2]) && return Future(CallMeta(Bool, ArgumentError, EFFECTS_THROWS, NoCallInfo()))
30173017
argtypes = argtypes[2:end]
30183018
atype = argtypes_to_type(argtypes)
3019-
matches = find_method_matches(interp, argtypes, atype; max_methods)
3020-
info = NoCallInfo()
3021-
if isa(matches, FailedMethodMatch)
3022-
rt = Bool # too many matches to analyze
3019+
if atype === Union{}
3020+
rt = Union{} # accidentally unreachable code
30233021
else
3024-
(; valid_worlds, applicable) = matches
3025-
update_valid_age!(sv, valid_worlds)
3026-
napplicable = length(applicable)
3027-
if napplicable == 0
3028-
rt = Const(false) # never any matches
3029-
elseif !fully_covering(matches) || any_ambig(matches)
3030-
# Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.
3031-
rt = Bool
3022+
matches = find_method_matches(interp, argtypes, atype; max_methods)
3023+
info = NoCallInfo()
3024+
if isa(matches, FailedMethodMatch)
3025+
rt = Bool # too many matches to analyze
30323026
else
3033-
rt = Const(true) # has applicable matches
3034-
end
3035-
if rt !== Bool
3036-
info = VirtualMethodMatchInfo(matches.info)
3027+
(; valid_worlds, applicable) = matches
3028+
update_valid_age!(sv, valid_worlds)
3029+
napplicable = length(applicable)
3030+
if napplicable == 0
3031+
rt = Const(false) # never any matches
3032+
elseif !fully_covering(matches) || any_ambig(matches)
3033+
# Account for the fact that we may encounter a MethodError with a non-covered or ambiguous signature.
3034+
rt = Bool
3035+
else
3036+
rt = Const(true) # has applicable matches
3037+
end
3038+
if rt !== Bool
3039+
info = VirtualMethodMatchInfo(matches.info)
3040+
end
30373041
end
30383042
end
30393043
return Future(CallMeta(rt, Union{}, EFFECTS_TOTAL, info))

Compiler/src/typeutils.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ has_extended_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isTy
5454
# certain combinations of `a` and `b` where one/both isa/are `Union`/`UnionAll` type(s)s.
5555
isnotbrokensubtype(@nospecialize(a), @nospecialize(b)) = (!iskindtype(b) || !isType(a) || hasuniquerep(a.parameters[1]) || b <: a)
5656

57-
argtypes_to_type(argtypes::Array{Any,1}) = Tuple{anymap(@nospecialize(a) -> isvarargtype(a) ? a : widenconst(a), argtypes)...}
57+
function argtypes_to_type(argtypes::Array{Any,1})
58+
argtypes = anymap(@nospecialize(a) -> isvarargtype(a) ? a : widenconst(a), argtypes)
59+
filter!(@nospecialize(x) -> !isvarargtype(x) || valid_as_lattice(unwrapva(x), true), argtypes)
60+
all(@nospecialize(x) -> isvarargtype(x) || valid_as_lattice(x, true), argtypes) || return Bottom
61+
return Tuple{argtypes...}
62+
end
5863

5964
function isknownlength(t::DataType)
6065
isvatuple(t) || return true

Compiler/test/inference.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6182,3 +6182,9 @@ end <: Any
61826182
end
61836183
return out
61846184
end == Union{Float64,DomainError}
6185+
6186+
# issue #56628
6187+
@test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}} ]) === Tuple{Int, UnitRange{Int}}
6188+
@test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64 ]) === Tuple{Int, UnitRange{Int}, Float64}
6189+
@test Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64, Memory{2} ]) === Union{}
6190+
@test Base.return_types(Tuple{Tuple{Int, Vararg{Pair{Any, Union{}}}}},) do x; Returns(true)(x...); end |> only === Bool

0 commit comments

Comments
 (0)