Skip to content

Commit 8a0e0c8

Browse files
authored
Fix typeassert dropping PartialStruct information (#36622)
There was a complaint on discourse that Generator splats weren't infering precisely enough [1]. I thought the recent improvement to abstract iteration precision would have fixed that, but that turns out not to be the case of a stupid reason. At the moment, any type assert (even something silly like `x::Any`), will drop `PartialStruct` information. Now, generators have an `::Tuple{Any, Any}` typeassert, which prevented the new iteration logic from working properly. This fixes typasserts, to not drop this information. The first couple of conditions that just return the original `PartialStruct` if the typeassert has no effect are doing most of the work here. As an add-on, I also threw in the logic to narrow the PartialStruct if the typeassert actually introduces additional information. It's not a particularly common code path, but might as well. [1] https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849
1 parent b07594d commit 8a0e0c8

File tree

2 files changed

+48
-10
lines changed

2 files changed

+48
-10
lines changed

base/compiler/tfuncs.jl

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -485,18 +485,38 @@ add_tfunc(typeof, 1, 1, typeof_tfunc, 0)
485485
function typeassert_tfunc(@nospecialize(v), @nospecialize(t))
486486
t = instanceof_tfunc(t)[1]
487487
t === Any && return v
488-
if isa(v, Const)
489-
if !has_free_typevars(t) && !isa(v.val, t)
490-
return Bottom
491-
end
492-
return v
493-
elseif isa(v, Conditional)
494-
if !(Bool <: t)
495-
return Bottom
488+
function typeassert_type_instance(@nospecialize(v), @nospecialize(t))
489+
if isa(v, Const)
490+
if !has_free_typevars(t) && !isa(v.val, t)
491+
return Bottom
492+
end
493+
return v
494+
elseif isa(v, PartialStruct)
495+
has_free_typevars(t) && return v
496+
widev = widenconst(v)
497+
if widev <: t
498+
return v
499+
elseif typeintersect(widev, t) === Bottom
500+
return Bottom
501+
end
502+
@assert widev <: Tuple
503+
new_fields = Vector{Any}(undef, length(v.fields))
504+
for i = 1:length(new_fields)
505+
new_fields[i] = typeassert_type_instance(v.fields[i], getfield_tfunc(t, Const(i)))
506+
if new_fields[i] === Bottom
507+
return Bottom
508+
end
509+
end
510+
return tuple_tfunc(new_fields)
511+
elseif isa(v, Conditional)
512+
if !(Bool <: t)
513+
return Bottom
514+
end
515+
return v
496516
end
497-
return v
517+
return typeintersect(widenconst(v), t)
498518
end
499-
return typeintersect(widenconst(v), t)
519+
return typeassert_type_instance(v, t)
500520
end
501521
add_tfunc(typeassert, 2, 2, typeassert_tfunc, 4)
502522

test/compiler/inference.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2716,3 +2716,21 @@ function f_apply_union_split(fs, x)
27162716
end
27172717

27182718
@test Base.return_types(f_apply_union_split, Tuple{Tuple{typeof(sqrt), typeof(abs)}, Int64}) == Any[Union{Int64, Float64}]
2719+
2720+
# Precision of typeassert with PartialStruct
2721+
function f_typ_assert(x::Int)
2722+
y = (x, 1)
2723+
y = y::Any
2724+
Val{y[2]}
2725+
end
2726+
@test Base.return_types(f_typ_assert, (Int,)) == Any[Type{Val{1}}]
2727+
2728+
function f_typ_assert2(x::Any)
2729+
y = (x::Union{Int, Float64}, 1)
2730+
y = y::Tuple{Int, Any}
2731+
(y[1], Val{y[2]}())
2732+
end
2733+
@test Base.return_types(f_typ_assert2, (Any,)) == Any[Tuple{Int, Val{1}}]
2734+
2735+
f_generator_splat(t::Tuple) = tuple((identity(l) for l in t)...)
2736+
@test Base.return_types(f_generator_splat, (Tuple{Symbol, Int64, Float64},)) == Any[Tuple{Symbol, Int64, Float64}]

0 commit comments

Comments
 (0)