Iβm encountering a strange type instability that I could distill to the following minimal code:
function unstable(rv,x0)
x1=copy(x0)
for t in 1:10
p::Int = prod(x0[j] for j in rv; init=1)
x1[1] = p == 1 ? 0 : 1
x0,x1 = x1,x0
end
return x0
end
@code_warntype
gives the following. The instability disappears if:
- If I set
p=1
instead of thep=prod(... )
- If I typeassert
x0
andx1
in the assignment, i.e.x0::Vector{Int},x1::Vector{Int} = x1,x0
instead ofx0,x1 = x1,x0
.
Any idea or explanation?
julia> @code_warntype unstable(fill(1,10),fill(1,10))
MethodInstance for unstable(::Vector{Int64}, ::Vector{Int64})
from unstable(rv, x0) @ Main REPL[103]:1
Arguments
#self#::Core.Const(unstable)
rv::Vector{Int64}
x0@_3::Vector{Int64}
Locals
@_4::Union{Nothing, Tuple{Int64, Int64}}
x1::Any
#109::var"#109#110"
t::Int64
p::Int64
x0@_9::Union{}
x0@_10::Union{}
x0@_11::Union{}
x0@_12::Union{Core.Box, Vector{Int64}}
@_13::Int64
Body::Any
1 ββ (x0@_12 = x0@_3)
β (x0@_12 = Core.Box(x0@_12::Vector{Int64}))
β Core.NewvarNode(:(@_4))
β Core.NewvarNode(:(x1))
β %5 = Core.isdefined(x0@_12::Core.Box, :contents)::Bool
ββββ goto #3 if not %5
2 ββ goto #4
3 ββ Core.NewvarNode(:(x0@_9))
ββββ x0@_9
4 ββ %10 = Core.getfield(x0@_12::Core.Box, :contents)::Any
β (x1 = Main.copy(%10))
β %12 = (1:10)::Core.Const(1:10)
β (@_4 = Base.iterate(%12))
β %14 = (@_4::Core.Const((1, 1)) === nothing)::Core.Const(false)
β %15 = Base.not_int(%14)::Core.Const(true)
ββββ goto #13 if not %15
5 ββ %17 = @_4::Tuple{Int64, Int64}
β (t = Core.getfield(%17, 1))
β %19 = Core.getfield(%17, 2)::Int64
β (#109 = %new(Main.:(var"#109#110"), x0@_12::Core.Box))
β %21 = #109::var"#109#110"
β %22 = Base.Generator(%21, rv)::Base.Generator{Vector{Int64}, var"#109#110"}
β %23 = (:init,)::Core.Const((:init,))
β %24 = Core.apply_type(Core.NamedTuple, %23)::Core.Const(NamedTuple{(:init,)})
β %25 = Core.tuple(1)::Core.Const((1,))
β %26 = (%24)(%25)::Core.Const((init = 1,))
β %27 = Core.kwcall(%26, Main.prod, %22)::Any
β %28 = Base.convert(Main.Int, %27)::Any
β (p = Core.typeassert(%28, Main.Int))
β %30 = (p == 1)::Bool
ββββ goto #7 if not %30
6 ββ (@_13 = 0)
ββββ goto #8
7 ββ (@_13 = 1)
8 ββ %35 = @_13::Int64
β Base.setindex!(x1, %35, 1)
β %37 = x1::Any
β %38 = Core.isdefined(x0@_12::Core.Box, :contents)::Bool
ββββ goto #10 if not %38
9 ββ goto #11
10 β Core.NewvarNode(:(x0@_10))
ββββ x0@_10
11 β %43 = Core.getfield(x0@_12::Core.Box, :contents)::Any
β Core.setfield!(x0@_12::Core.Box, :contents, %37)
β (x1 = %43)
β (@_4 = Base.iterate(%12, %19))
β %47 = (@_4 === nothing)::Bool
β %48 = Base.not_int(%47)::Bool
ββββ goto #13 if not %48
12 β goto #5
13 β %51 = Core.isdefined(x0@_12::Core.Box, :contents)::Bool
ββββ goto #15 if not %51
14 β goto #16
15 β Core.NewvarNode(:(x0@_11))
ββββ x0@_11
16 β %56 = Core.getfield(x0@_12::Core.Box, :contents)::Any
ββββ return %56