Skip to content

Commit c5e4621

Browse files
authored
inference: refine PartialStruct with declared method signature (#50590)
At present, in very rare cases, `PartialStruct` used for const-prop' might have type information that's less strict than type information that can be derived from the method's type signature, e.g.: ```julia Base.@constprop :aggressive function refine_partial_struct((a, b)::Tuple{String,Int}) if iszero(b) println("b=0") # to prevent semi-concrete eval return nothing else return a end end @test Base.return_types((AbstractString,)) do s refine_partial_struct((s, 42)) end |> only === String ``` This commit enhances the accuracy of const-prop' by propagating `tmeet` of `PartialStruct` and the declared type in such situations.
1 parent 0bf560a commit c5e4621

File tree

3 files changed

+36
-3
lines changed

3 files changed

+36
-3
lines changed

base/compiler/abstractlattice.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,7 @@ end
249249
isa(x, Const) && return true
250250
return is_forwardable_argtype(widenlattice(𝕃), x)
251251
end
252-
@nospecializeinfer function is_forwardable_argtype(::JLTypeLattice, @nospecialize x)
253-
return false
254-
end
252+
@nospecializeinfer is_forwardable_argtype(::JLTypeLattice, @nospecialize x) = false
255253

256254
"""
257255
widenreturn(𝕃ᵢ::AbstractLattice, @nospecialize(rt), info::BestguessInfo) -> new_bestguess

base/compiler/inferenceresult.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ function pick_const_args!(𝕃::AbstractLattice, cache_argtypes::Vector{Any}, ov
6161
cache_argtype = cache_argtypes[i]
6262
if !is_argtype_match(𝕃, given_argtype, cache_argtype, false)
6363
# prefer the argtype we were given over the one computed from `linfo`
64+
if (isa(given_argtype, PartialStruct) && isa(cache_argtype, Type) &&
65+
!(𝕃, given_argtype, cache_argtype))
66+
# if the type information of this `PartialStruct` is less strict than
67+
# declared method signature, narrow it down using `tmeet`
68+
given_argtype = tmeet(𝕃, given_argtype, cache_argtype)
69+
end
6470
cache_argtypes[i] = given_argtype
6571
overridden_by_const[i] = true
6672
end

test/compiler/inference.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5030,3 +5030,32 @@ h_issue50544(x::T) where T = g_issue50544(f_issue50544(T, 1), f_issue50544(T, 2,
50305030
let x = Issue50544((1, Issue50544((2.0, 'x'))))
50315031
@test only(Base.return_types(h_issue50544, (typeof(x),))) == Type{Issue50544{Tuple{Int,Float64}}}
50325032
end
5033+
5034+
# refine const-prop'ed `PartialStruct` with declared method signature type
5035+
Base.@constprop :aggressive function refine_partial_struct1((a, b)::Tuple{String,Int})
5036+
if iszero(b)
5037+
println("b=0") # to prevent semi-concrete eval
5038+
return nothing
5039+
else
5040+
return a
5041+
end
5042+
end
5043+
@test Base.return_types() do s::AbstractString
5044+
refine_partial_struct1((s, 42))
5045+
end |> only === String
5046+
5047+
function refine_partial_struct2(xs::Union{Int,String,Symbol}...)
5048+
first(xs) isa Int && iszero(first(xs)) && return nothing
5049+
for x in xs[2:end]
5050+
if x isa String
5051+
continue
5052+
else
5053+
return nothing
5054+
end
5055+
end
5056+
return string(length(xs))
5057+
end
5058+
@test Base.return_types() do s::AbstractString
5059+
refine_partial_struct2(42, s)
5060+
end |> only === String
5061+
# JET.test_call(s::AbstractString->Base._string(s, 'c'))

0 commit comments

Comments
 (0)