Skip to content

Commit 296bdfb

Browse files
vtjnashpull[bot]
authored andcommitted
improve apply_type_tfunc accuracy in rare case (JuliaLang#49069)
In the unlikely event this call fails, we can either confidently conclude the result will always fail and stop inference immediately there. Or we can at least conclude that the base type is confidently known, which can potentially improve ml-matches performance later by excluding Union{} or other subtypes.
1 parent 9633917 commit 296bdfb

File tree

2 files changed

+36
-7
lines changed

2 files changed

+36
-7
lines changed

base/compiler/tfuncs.jl

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,7 @@ function apply_type_nothrow(𝕃::AbstractLattice, argtypes::Vector{Any}, @nospe
16281628
(headtype === Union) && return true
16291629
isa(rt, Const) && return true
16301630
u = headtype
1631+
# TODO: implement optimization for isvarargtype(u) and istuple occurences (which are valid but are not UnionAll)
16311632
for i = 2:length(argtypes)
16321633
isa(u, UnionAll) || return false
16331634
ai = widenconditional(argtypes[i])
@@ -1747,6 +1748,9 @@ const _tvarnames = Symbol[:_A, :_B, :_C, :_D, :_E, :_F, :_G, :_H, :_I, :_J, :_K,
17471748
end
17481749
ua = ua.body
17491750
end
1751+
if largs > outer_start && isa(headtype, UnionAll) # e.g. !isvarargtype(ua) && !istuple
1752+
return Bottom # too many arguments
1753+
end
17501754
outer_start = outer_start - largs + 1
17511755

17521756
varnamectr = 1
@@ -1815,19 +1819,40 @@ const _tvarnames = Symbol[:_A, :_B, :_C, :_D, :_E, :_F, :_G, :_H, :_I, :_J, :_K,
18151819
push!(outervars, v)
18161820
end
18171821
end
1818-
if isa(ua, UnionAll)
1822+
if ua isa UnionAll
18191823
ua = ua.body
1820-
else
1821-
ua = nothing
1824+
#otherwise, sometimes ua isa Vararg (Core.TypeofVararg) or Tuple (DataType)
18221825
end
18231826
end
18241827
local appl
18251828
try
18261829
appl = apply_type(headtype, tparams...)
18271830
catch ex
1828-
# type instantiation might fail if one of the type parameters
1829-
# doesn't match, which could happen if a type estimate is too coarse
1830-
return isvarargtype(headtype) ? TypeofVararg : Type{<:headtype}
1831+
# type instantiation might fail if one of the type parameters doesn't
1832+
# match, which could happen only if a type estimate is too coarse
1833+
# and might guess a concrete value while the actual type for it is Bottom
1834+
if !uncertain
1835+
return Union{}
1836+
end
1837+
canconst = false
1838+
uncertain = true
1839+
empty!(outervars)
1840+
outer_start = 1
1841+
# FIXME: if these vars are substituted with TypeVar here, the result
1842+
# might be wider than the input, so should we use the `.name.wrapper`
1843+
# object here instead, to replace all of these outervars with
1844+
# unconstrained ones? Note that this code is nearly unreachable though,
1845+
# and possibly should simply return Union{} here also, since
1846+
# `apply_type` is already quite conservative about detecting and
1847+
# throwing errors.
1848+
appl = headtype
1849+
if isa(appl, UnionAll)
1850+
for _ = 1:largs
1851+
appl = appl::UnionAll
1852+
push!(outervars, appl.var)
1853+
appl = appl.body
1854+
end
1855+
end
18311856
end
18321857
!uncertain && canconst && return Const(appl)
18331858
if isvarargtype(appl)

test/compiler/inference.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2648,10 +2648,14 @@ end |> only === Int
26482648
# https://github.com/JuliaLang/julia/issues/47089
26492649
import Core: Const
26502650
import Core.Compiler: apply_type_tfunc
2651-
struct Issue47089{A,B} end
2651+
struct Issue47089{A<:Number,B<:Number} end
26522652
let 𝕃 = Core.Compiler.fallback_lattice
26532653
A = Type{<:Integer}
26542654
@test apply_type_tfunc(𝕃, Const(Issue47089), A, A) <: (Type{Issue47089{A,B}} where {A<:Integer, B<:Integer})
2655+
@test apply_type_tfunc(𝕃, Const(Issue47089), Const(Int), Const(Int), Const(Int)) === Union{}
2656+
@test apply_type_tfunc(𝕃, Const(Issue47089), Const(String)) === Union{}
2657+
@test apply_type_tfunc(𝕃, Const(Issue47089), Const(AbstractString)) === Union{}
2658+
@test apply_type_tfunc(𝕃, Const(Issue47089), Type{Ptr}, Type{Ptr{T}} where T) === Base.rewrap_unionall(Type{Issue47089.body.body}, Issue47089)
26552659
end
26562660
@test only(Base.return_types(keys, (Dict{String},))) == Base.KeySet{String, T} where T<:(Dict{String})
26572661
@test only(Base.return_types((r)->similar(Array{typeof(r[])}, 1), (Base.RefValue{Array{Int}},))) == Vector{<:Array{Int}}

0 commit comments

Comments
 (0)