Skip to content

Commit 2cee898

Browse files
committed
inference: avoid inferring unreachable code methods
Avoids causing issues in matching_cache_argtypes/tuple_tfunc with invalid contents appearing in the Tuple parameters after intersections (such as Int, tuple of Symbol, etc). Also sharpen valid_as_lattice / instanceof_tfunc to be able to filter out and reject types that cannot appear as tags at runtime, except where they are used for non-tag queries (like fieldtype_tfunc and subtype_tfunc). Fixes #51228 (part 2)
1 parent 13d3efb commit 2cee898

File tree

9 files changed

+96
-71
lines changed

9 files changed

+96
-71
lines changed

base/compiler/abstractinterpretation.jl

+35-22
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,10 @@ function abstract_call_method(interp::AbstractInterpreter,
485485
return MethodCallResult(Any, false, false, nothing, Effects())
486486
end
487487
sigtuple = unwrap_unionall(sig)
488-
sigtuple isa DataType || return MethodCallResult(Any, false, false, nothing, Effects())
488+
sigtuple isa DataType ||
489+
return MethodCallResult(Any, false, false, nothing, Effects())
490+
all(@nospecialize(x) -> valid_as_lattice(unwrapva(x), true), sigtuple.parameters) ||
491+
return MethodCallResult(Union{}, false, false, nothing, EFFECTS_THROWS) # catch bad type intersections early
489492

490493
if is_nospecializeinfer(method)
491494
sig = get_nospecializeinfer_sig(method, sig, sparams)
@@ -1365,25 +1368,35 @@ function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft)
13651368
end
13661369
if isa(tti, Union)
13671370
utis = uniontypes(tti)
1368-
if any(@nospecialize(t) -> !isa(t, DataType) || !(t <: Tuple) || !isknownlength(t), utis)
1369-
return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects())
1370-
end
1371-
ltp = length((utis[1]::DataType).parameters)
1372-
for t in utis
1373-
if length((t::DataType).parameters) != ltp
1374-
return AbstractIterationResult(Any[Vararg{Any}], nothing)
1371+
# refine the Union to remove elements that are not valid tags for objects
1372+
filter!(@nospecialize(x) -> valid_as_lattice(x, true), utis)
1373+
if length(utis) == 0
1374+
return AbstractIterationResult(Any[], nothing) # oops, this statement was actually unreachable
1375+
elseif length(utis) == 1
1376+
tti = utis[1]
1377+
tti0 = rewrap_unionall(tti, tti0)
1378+
else
1379+
if any(@nospecialize(t) -> !isa(t, DataType) || !(t <: Tuple) || !isknownlength(t), utis)
1380+
return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects())
13751381
end
1376-
end
1377-
result = Any[ Union{} for _ in 1:ltp ]
1378-
for t in utis
1379-
tps = (t::DataType).parameters
1380-
_all(valid_as_lattice, tps) || continue
1381-
for j in 1:ltp
1382-
result[j] = tmerge(result[j], rewrap_unionall(tps[j], tti0))
1382+
ltp = length((utis[1]::DataType).parameters)
1383+
for t in utis
1384+
if length((t::DataType).parameters) != ltp
1385+
return AbstractIterationResult(Any[Vararg{Any}], nothing)
1386+
end
1387+
end
1388+
result = Any[ Union{} for _ in 1:ltp ]
1389+
for t in utis
1390+
tps = (t::DataType).parameters
1391+
for j in 1:ltp
1392+
@assert valid_as_lattice(tps[j], true)
1393+
result[j] = tmerge(result[j], rewrap_unionall(tps[j], tti0))
1394+
end
13831395
end
1396+
return AbstractIterationResult(result, nothing)
13841397
end
1385-
return AbstractIterationResult(result, nothing)
1386-
elseif tti0 <: Tuple
1398+
end
1399+
if tti0 <: Tuple
13871400
if isa(tti0, DataType)
13881401
return AbstractIterationResult(Any[ p for p in tti0.parameters ], nothing)
13891402
elseif !isa(tti, DataType)
@@ -1647,7 +1660,7 @@ end
16471660
return isa_condition(xt, ty, max_union_splitting)
16481661
end
16491662
@inline function isa_condition(@nospecialize(xt), @nospecialize(ty), max_union_splitting::Int)
1650-
tty_ub, isexact_tty = instanceof_tfunc(ty)
1663+
tty_ub, isexact_tty = instanceof_tfunc(ty, true)
16511664
tty = widenconst(xt)
16521665
if isexact_tty && !isa(tty_ub, TypeVar)
16531666
tty_lb = tty_ub # TODO: this would be wrong if !isexact_tty, but instanceof_tfunc doesn't preserve this info
@@ -1657,7 +1670,7 @@ end
16571670
# `typeintersect` may be unable narrow down `Type`-type
16581671
thentype = tty_ub
16591672
end
1660-
valid_as_lattice(thentype) || (thentype = Bottom)
1673+
valid_as_lattice(thentype, true) || (thentype = Bottom)
16611674
elsetype = typesubtract(tty, tty_lb, max_union_splitting)
16621675
return ConditionalTypes(thentype, elsetype)
16631676
end
@@ -1903,7 +1916,7 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn
19031916
ft′ = argtype_by_index(argtypes, 2)
19041917
ft = widenconst(ft′)
19051918
ft === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
1906-
(types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3))
1919+
(types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false)
19071920
isexact || return CallMeta(Any, Effects(), NoCallInfo())
19081921
unwrapped = unwrap_unionall(types)
19091922
if types === Bottom || !(unwrapped isa DataType) || unwrapped.name !== Tuple.name
@@ -2322,7 +2335,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
23222335
(; rt, effects) = abstract_eval_call(interp, e, vtypes, sv)
23232336
t = rt
23242337
elseif ehead === :new
2325-
t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))
2338+
t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv), true)
23262339
ut = unwrap_unionall(t)
23272340
consistent = noub = ALWAYS_FALSE
23282341
nothrow = false
@@ -2387,7 +2400,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp
23872400
end
23882401
effects = Effects(EFFECTS_TOTAL; consistent, nothrow, noub)
23892402
elseif ehead === :splatnew
2390-
t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))
2403+
t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv), true)
23912404
nothrow = false # TODO: More precision
23922405
if length(e.args) == 2 && isconcretedispatch(t) && !ismutabletype(t)
23932406
at = abstract_eval_value(interp, e.args[2], vtypes, sv)

base/compiler/abstractlattice.jl

+5-3
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,18 @@ is_valid_lattice_norec(::InferenceLattice, @nospecialize(elem)) = isa(elem, Limi
9898
"""
9999
tmeet(𝕃::AbstractLattice, a, b::Type)
100100
101-
Compute the lattice meet of lattice elements `a` and `b` over the lattice `𝕃`.
102-
If `𝕃` is `JLTypeLattice`, this is equivalent to type intersection.
101+
Compute the lattice meet of lattice elements `a` and `b` over the lattice `𝕃`,
102+
dropping any results that will not be inhabited at runtime.
103+
If `𝕃` is `JLTypeLattice`, this is equivalent to type intersection plus the
104+
elimination of results that have no concrete subtypes.
103105
Note that currently `b` is restricted to being a type
104106
(interpreted as a lattice element in the `JLTypeLattice` sub-lattice of `𝕃`).
105107
"""
106108
function tmeet end
107109

108110
function tmeet(::JLTypeLattice, @nospecialize(a::Type), @nospecialize(b::Type))
109111
ti = typeintersect(a, b)
110-
valid_as_lattice(ti) || return Bottom
112+
valid_as_lattice(ti, true) || return Bottom
111113
return ti
112114
end
113115

base/compiler/optimize.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ function new_expr_effect_flags(𝕃ₒ::AbstractLattice, args::Vector{Any}, src:
243243
Targ = args[1]
244244
atyp = argextype(Targ, src)
245245
# `Expr(:new)` of unknown type could raise arbitrary TypeError.
246-
typ, isexact = instanceof_tfunc(atyp)
246+
typ, isexact = instanceof_tfunc(atyp, true)
247247
if !isexact
248248
atyp = unwrap_unionall(widenconst(atyp))
249249
if isType(atyp) && isTypeDataType(atyp.parameters[1])
@@ -335,7 +335,7 @@ function stmt_effect_flags(𝕃ₒ::AbstractLattice, @nospecialize(stmt), @nospe
335335
elseif head === :new_opaque_closure
336336
length(args) < 4 && return (false, false, false)
337337
typ = argextype(args[1], src)
338-
typ, isexact = instanceof_tfunc(typ)
338+
typ, isexact = instanceof_tfunc(typ, true)
339339
isexact || return (false, false, false)
340340
(𝕃ₒ, typ, Tuple) || return (false, false, false)
341341
rt_lb = argextype(args[2], src)

base/compiler/ssair/inlining.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1200,7 +1200,7 @@ function handle_invoke_call!(todo::Vector{Pair{Int,Any}},
12001200
end
12011201

12021202
function invoke_signature(argtypes::Vector{Any})
1203-
ft, argtyps = widenconst(argtypes[2]), instanceof_tfunc(widenconst(argtypes[3]))[1]
1203+
ft, argtyps = widenconst(argtypes[2]), instanceof_tfunc(widenconst(argtypes[3]), false)[1]
12041204
return rewrap_unionall(Tuple{ft, unwrap_unionall(argtyps).parameters...}, argtyps)
12051205
end
12061206

base/compiler/ssair/passes.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1756,7 +1756,7 @@ function adce_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing)
17561756
else
17571757
if is_known_call(stmt, typeassert, compact) && length(stmt.args) == 3
17581758
# nullify safe `typeassert` calls
1759-
ty, isexact = instanceof_tfunc(argextype(stmt.args[3], compact))
1759+
ty, isexact = instanceof_tfunc(argextype(stmt.args[3], compact), true)
17601760
if isexact && (𝕃ₒ, argextype(stmt.args[2], compact), ty)
17611761
compact[idx] = nothing
17621762
continue

0 commit comments

Comments
 (0)