diff --git a/base/compiler/typeutils.jl b/base/compiler/typeutils.jl index ebb06a33a2d74..d6eb7305b1c8d 100644 --- a/base/compiler/typeutils.jl +++ b/base/compiler/typeutils.jl @@ -70,6 +70,15 @@ function typesubtract(@nospecialize(a), @nospecialize(b)) if isa(a, Union) return Union{typesubtract(a.a, b), typesubtract(a.b, b)} + elseif a isa DataType + if b isa DataType + if a.name === b.name === Tuple.name && length(a.types) == length(b.types) + ta = switchtupleunion(a) + if length(ta) > 1 + return typesubtract(Union{ta...}, b) + end + end + end end return a # TODO: improve this bound? end diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 26371e7927005..fd2e6138e561d 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -2545,3 +2545,44 @@ end @test only(Base.code_typed(pickvarnames, (Vector{Any},), optimize=false))[2] == Tuple{Vararg{Union{Symbol, Tuple{Vararg{Union{Symbol, Tuple}}}}}} @test map(>:, [Int], [Int]) == [true] + +# issue 35566 +module Issue35566 +function step(acc, x) + xs, = acc + y = x > 0.0 ? x : missing + if y isa eltype(xs) + ys = push!(xs, y) + else + ys = vcat(xs, [y]) + end + return (ys,) +end + +function probe(y) + if y isa Tuple{Vector{Missing}} + return Val(:missing) + else + return Val(:expected) + end +end + +function _foldl_iter(rf, val::T, iter, state) where {T} + while true + ret = iterate(iter, state) + ret === nothing && break + x, state = ret + y = rf(val, x) + if y isa T + val = y + else + return probe(y) + end + end + return Val(:expected) +end + +f() = _foldl_iter(step, (Missing[],), [0.0], 1) +end +@test Core.Compiler.typesubtract(Tuple{Union{Int,Char}}, Tuple{Char}) == Tuple{Int} +@test Base.return_types(Issue35566.f) == [Val{:expected}]