Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MWE: if x isa T does not narrow the type in else block #35566

Closed
tkf opened this issue Apr 23, 2020 · 1 comment · Fixed by #35600
Closed

MWE: if x isa T does not narrow the type in else block #35566

tkf opened this issue Apr 23, 2020 · 1 comment · Fixed by #35600
Labels
compiler:inference Type inference

Comments

@tkf
Copy link
Member

tkf commented Apr 23, 2020

This snippet

@noinline 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

@noinline 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 _foldl_iter(rf, y, iter, state)
        end
    end
    return val
end

@code_typed optimize=false _foldl_iter(step, (Missing[],), [0.0], 1)

prints

CodeInfo(
1$(Expr(:meta, :noinline))
│         (val@_10 = val@_3)::Tuple{Array{Missing,1}}
└──       (state@_11 = state@_5)::Int64
2 ┄       goto #9 if not true
3 ─       Core.NewvarNode(:(x))::Any
│         Core.NewvarNode(:(@_8))::Any
│         Core.NewvarNode(:(y))::Any
│         (ret = Main.iterate(iter, state@_11))::Union{Nothing, Tuple{Float64,Int64}}%9  = (ret === Main.nothing)::Bool
└──       goto #5 if not %9
4 ─       goto #9
5%12 = Base.indexed_iterate(ret::Tuple{Float64,Int64}, 1)::Core.Compiler.PartialStruct(Tuple{Float64,Int64}, Any[Float64, Core.Compiler.Const(2, false)])
│         (x = Core.getfield(%12, 1))::Float64
│         (@_8 = Core.getfield(%12, 2))::Core.Compiler.Const(2, false)
│   %15 = Base.indexed_iterate(ret::Tuple{Float64,Int64}, 2, @_8::Core.Compiler.Const(2, false))::Core.Compiler.PartialStruct(Tuple{Int64,Int64}, Any[Int64, Core.Compiler.Const(3, false)])
│         (state@_11 = Core.getfield(%15, 1))::Int64
│         (y = (rf)(val@_10, x))::Tuple{Union{Array{Missing,1}, Array{Union{Missing, Float64},1}}}
│   %18 = (y isa $(Expr(:static_parameter, 1)))::Bool
└──       goto #7 if not %18
6 ─       (val@_10 = y::Tuple{Array{Missing,1}})::Tuple{Array{Missing,1}}
└──       goto #8
7%22 = Main._foldl_iter(rf, y, iter, state@_11)::Tuple{Union{Array{Missing,1}, Array{Union{Missing, Float64},1}}}
└──       return %22
8 ─       goto #2
9return val@_10
) => Tuple{Union{Array{Missing,1}, Array{Union{Missing, Float64},1}}}

I expect %22 = Main._foldl_iter(rf, y, iter, state@_11)::Tuple{Array{Union{Missing, Float64},1}} instead of %22 = Main._foldl_iter(rf, y, iter, state@_11)::Tuple{Union{Array{Missing,1}, Array{Union{Missing, Float64},1}}} which has a tuple-of-union. This seems to be due that the argument y in #7 is inferred to be Tuple{Union{Array{Missing,1}, Array{Union{Missing, Float64},1}}}. (Indeed, this is what @descend shows me. Also, I see a corresponding @jl_apply_generic in the LLVM IR. IIUC this is a sign of a dynamic dispatch.)

The type is narrowed as expected if I tweak the example to avoid using intermediate tuple:

@noinline function step2(xs, x)
    y = x > 0.0 ? x : missing
    if y isa eltype(xs)
        ys = push!(xs, y)
    else
        ys = vcat(xs, [y])
    end
    return ys
end

@code_typed optimize=false _foldl_iter(step2, Missing[], [0.0], 1)

prints

...
7%22 = Main._foldl_iter(rf, y::Array{Union{Missing, Float64},1}, iter, state@_11)::Array{Union{Missing, Float64},1}
...

It'd be great if this works in the first example too.

Checked with Julia 1.5.0-DEV.630.

@tkf
Copy link
Member Author

tkf commented Sep 24, 2020

This is re-closed by #37714, I guess?

@vtjnash vtjnash closed this as completed Sep 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:inference Type inference
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants