From b3e10429e4f61b5c0e6a683993133976a1803a12 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 16 Dec 2020 14:53:21 -0500 Subject: [PATCH] fix #38888, pessimistic sparam inference with concrete upper bound --- base/compiler/utilities.jl | 32 +++++++++++++++++++++++++++++++- test/compiler/inference.jl | 10 ++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index 60038cad7675d..e047c7d83fac3 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -139,15 +139,45 @@ end const nonfunction_mt = typename(SimpleVector).mt function get_compileable_sig(method::Method, @nospecialize(atypes), sparams::SimpleVector) - isa(atypes, DataType) || return Nothing + isa(atypes, DataType) || return nothing mt = ccall(:jl_method_table_for, Any, (Any,), atypes) mt === nothing && return nothing return ccall(:jl_normalize_to_compilable_sig, Any, (Any, Any, Any, Any), mt, atypes, sparams, method) end +# eliminate UnionAll vars that might be degenerate due to having identical bounds, +# or a concrete upper bound and appearing covariantly. +function subst_trivial_bounds(@nospecialize(atypes)) + if !isa(atypes, UnionAll) + return atypes + end + v = atypes.var + if isconcretetype(v.ub) || v.lb === v.ub + return subst_trivial_bounds(atypes{v.ub}) + end + return UnionAll(v, subst_trivial_bounds(atypes.body)) +end + +# If removing trivial vars from atypes results in an equivalent type, use that +# instead. Otherwise we can get a case like issue #38888, where a signature like +# f(x::S) where S<:Int +# gets cached and matches a concrete dispatch case. +function normalize_typevars(method::Method, @nospecialize(atypes), sparams::SimpleVector) + at2 = subst_trivial_bounds(atypes) + if at2 !== atypes && at2 == atypes + atypes = at2 + sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), at2, method.sig)::SimpleVector + sparams = sp_[2]::SimpleVector + end + return atypes, sparams +end + # get a handle to the unique specialization object representing a particular instantiation of a call function specialize_method(method::Method, @nospecialize(atypes), sparams::SimpleVector, preexisting::Bool=false, compilesig::Bool=false) + if isa(atypes, UnionAll) + atypes, sparams = normalize_typevars(method, atypes, sparams) + end if compilesig new_atypes = get_compileable_sig(method, atypes, sparams) new_atypes === nothing && return nothing diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 75027f4841209..304a704856ebb 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -2979,3 +2979,13 @@ gVarargInt(x::Int) = 1 gVarargInt(x) = 2 fVarargInt(::Tuple{Vararg{Int, N}}) where {N} = Val{gVarargInt(N)}() @test only(Base.return_types(fVarargInt, Tuple{Tuple{Vararg{Int}}})) == Val{1} + +# issue #38888 +struct S38888{T} + S38888(x::S) where {S<:Int} = new{S}() + S38888(x::S, y) where {S2<:Int,S<:S2} = new{S}() +end +f38888() = S38888(Base.inferencebarrier(3)) +@test f38888() isa S38888 +g38888() = S38888(Base.inferencebarrier(3), nothing) +@test g38888() isa S38888