Skip to content

Commit 6e2e6d0

Browse files
authored
when widening tuple types in tmerge, only widen the complex parts (#50929)
This is the part of #50927 required to fix #49249. Specifically, before this change `tmerge(Tuple{Any, Int}, Nothing)` would be `Union{Nothing, Tuple{Any, Int}}` but `tmerge(Tuple{BIG_UNION, Int}, Nothing)` would be `Union{Nothing, Tuple{Any, Any}}`. This feels bad intuitively because giving the compiler more type information led it to forget type information that it already knew about, and is especially damaging because it led to unnecessary type instability when iterating tuples with complex element types (because the iterator state should be inferrable as an `Int` even if you have no idea what the tuple type is). This is tagged for backport to 1.10 since it is a relatively unobtrusive change and it fixes the string regression in a more proper way.
1 parent 30a73de commit 6e2e6d0

File tree

2 files changed

+28
-12
lines changed

2 files changed

+28
-12
lines changed

base/compiler/typelimits.jl

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -764,23 +764,24 @@ end
764764
return u
765765
end
766766
# don't let the slow widening of Tuple cause the whole type to grow too fast
767+
# Specifically widen Tuple{..., Union{lots of stuff}...} to Tuple{..., Any, ...}
767768
for i in 1:length(types)
768769
if typenames[i] === Tuple.name
769-
widen = unwrap_unionall(types[i])
770-
if isa(widen, DataType) && !isvatuple(widen)
771-
widen = NTuple{length(widen.parameters), Any}
772-
else
773-
widen = Tuple
774-
end
775-
types[i] = widen
776-
u = Union{types...}
777-
if issimpleenoughtype(u)
778-
return u
770+
ti = types[i]
771+
tip = (unwrap_unionall(types[i])::DataType).parameters
772+
lt = length(tip)
773+
p = Vector{Any}(undef, lt)
774+
for j = 1:lt
775+
ui = tip[j]
776+
p[j] = (unioncomplexity(ui)==0) ? ui : isvarargtype(ui) ? Vararg : Any
779777
end
780-
break
778+
types[i] = rewrap_unionall(Tuple{p...}, ti)
781779
end
782780
end
783-
# finally, just return the widest possible type
781+
u = Union{types...}
782+
if issimpleenoughtype(u)
783+
return u
784+
end
784785
return Any
785786
end
786787

test/compiler/inference.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,21 @@ tmerge_test(Tuple{}, Tuple{Complex, Vararg{Union{ComplexF32, ComplexF64}}},
213213
@test Core.Compiler.tmerge(Base.BitIntegerType, Union{}) === Base.BitIntegerType
214214
@test Core.Compiler.tmerge(Union{}, Base.BitIntegerType) === Base.BitIntegerType
215215
@test Core.Compiler.tmerge(Core.Compiler.fallback_ipo_lattice, Core.Compiler.InterConditional(1, Int, Union{}), Core.Compiler.InterConditional(2, String, Union{})) === Core.Compiler.Const(true)
216+
# test issue behind https://github.com/JuliaLang/julia/issues/50458
217+
@test Core.Compiler.tmerge(Nothing, Tuple{Base.BitInteger, Int}) == Union{Nothing, Tuple{Any, Int}}
218+
@test Core.Compiler.tmerge(Nothing, Tuple{Union{Char, String, SubString{String}, Symbol}, Int}) == Union{Nothing, Tuple{Any, Int}}
219+
@test Core.Compiler.tmerge(Nothing, Tuple{Integer, Int}) == Union{Nothing, Tuple{Integer, Int}}
220+
221+
# test that recursively more complicated types don't widen all the way to Any when there is a useful valid type upper bound
222+
# Specificially test with base types of a trivial type, a simple union, a complicated union, and a tuple.
223+
for T in (Nothing, Base.BitInteger, Union{Int, Int32, Int16, Int8}, Tuple{Int, Int})
224+
Ta, Tb = T, T
225+
for i in 1:10
226+
Ta = Union{Tuple{Ta}, Nothing}
227+
Tb = Core.Compiler.tmerge(Tuple{Tb}, Nothing)
228+
@test Ta <: Tb <: Union{Nothing, Tuple}
229+
end
230+
end
216231

217232
struct SomethingBits
218233
x::Base.BitIntegerType

0 commit comments

Comments
 (0)