Skip to content

Commit a88c435

Browse files
authored
fix #38888, pessimistic sparam inference with concrete upper bound (#38899)
1 parent 17de527 commit a88c435

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

base/compiler/utilities.jl

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,45 @@ end
139139
const nonfunction_mt = typename(SimpleVector).mt
140140

141141
function get_compileable_sig(method::Method, @nospecialize(atypes), sparams::SimpleVector)
142-
isa(atypes, DataType) || return Nothing
142+
isa(atypes, DataType) || return nothing
143143
mt = ccall(:jl_method_table_for, Any, (Any,), atypes)
144144
mt === nothing && return nothing
145145
return ccall(:jl_normalize_to_compilable_sig, Any, (Any, Any, Any, Any),
146146
mt, atypes, sparams, method)
147147
end
148148

149+
# eliminate UnionAll vars that might be degenerate due to having identical bounds,
150+
# or a concrete upper bound and appearing covariantly.
151+
function subst_trivial_bounds(@nospecialize(atypes))
152+
if !isa(atypes, UnionAll)
153+
return atypes
154+
end
155+
v = atypes.var
156+
if isconcretetype(v.ub) || v.lb === v.ub
157+
return subst_trivial_bounds(atypes{v.ub})
158+
end
159+
return UnionAll(v, subst_trivial_bounds(atypes.body))
160+
end
161+
162+
# If removing trivial vars from atypes results in an equivalent type, use that
163+
# instead. Otherwise we can get a case like issue #38888, where a signature like
164+
# f(x::S) where S<:Int
165+
# gets cached and matches a concrete dispatch case.
166+
function normalize_typevars(method::Method, @nospecialize(atypes), sparams::SimpleVector)
167+
at2 = subst_trivial_bounds(atypes)
168+
if at2 !== atypes && at2 == atypes
169+
atypes = at2
170+
sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), at2, method.sig)::SimpleVector
171+
sparams = sp_[2]::SimpleVector
172+
end
173+
return atypes, sparams
174+
end
175+
149176
# get a handle to the unique specialization object representing a particular instantiation of a call
150177
function specialize_method(method::Method, @nospecialize(atypes), sparams::SimpleVector, preexisting::Bool=false, compilesig::Bool=false)
178+
if isa(atypes, UnionAll)
179+
atypes, sparams = normalize_typevars(method, atypes, sparams)
180+
end
151181
if compilesig
152182
new_atypes = get_compileable_sig(method, atypes, sparams)
153183
new_atypes === nothing && return nothing

test/compiler/inference.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2979,3 +2979,13 @@ gVarargInt(x::Int) = 1
29792979
gVarargInt(x) = 2
29802980
fVarargInt(::Tuple{Vararg{Int, N}}) where {N} = Val{gVarargInt(N)}()
29812981
@test only(Base.return_types(fVarargInt, Tuple{Tuple{Vararg{Int}}})) == Val{1}
2982+
2983+
# issue #38888
2984+
struct S38888{T}
2985+
S38888(x::S) where {S<:Int} = new{S}()
2986+
S38888(x::S, y) where {S2<:Int,S<:S2} = new{S}()
2987+
end
2988+
f38888() = S38888(Base.inferencebarrier(3))
2989+
@test f38888() isa S38888
2990+
g38888() = S38888(Base.inferencebarrier(3), nothing)
2991+
@test g38888() isa S38888

0 commit comments

Comments
 (0)