MilesCranmer / DispatchDoctor.jl

The dispatch doctor prescribes type stability
Apache License 2.0
128 stars 6 forks source link

type-stable code is considered unstable #5

Closed matthias314 closed 1 month ago

matthias314 commented 1 month ago

Sorry for posting it to Discourse. I've shortened the example, but I haven't tried to prove that the new one is indeed minimal.

struct T{U}
    m::U
end

@stable function f(m::Int, iter)
    for n in iter
        m |= 0
    end
    T(m)
end
julia> f(0, ())
ERROR: TypeInstabilityError: Instability detected in `f` defined at REPL[4]:1 with arguments `(Int64, Tuple{})`. Inferred to be `T`, which is not a concrete type.
matthias314 commented 1 month ago

Here is another example:

@stable function g(n)
    n = Int(n)::Int
    n
end
julia> g(1)
ERROR: TypeInstabilityError: Instability detected in `g` defined at REPL[2]:1 with arguments `(Int64,)`. Inferred to be `Any`, which is not a concrete type.
MilesCranmer commented 1 month ago

Oops, sorry, just saw this! (I posted another example on the discourse. Indeed this seems very real!)

I think it has to do with the closure manipulating a variable in the function argument

@stable function g(n)
    n = Int(n)::Int
    n
end

gets transformed to

function g(n)
    function closure()
        n = Int(n)::Int
        n
    end
    closure()
end

(Excluding the inference checks). So it's something about how n is both a function argument and is being modified by the closure...

This is similar to the reason why https://github.com/c42f/FastClosures.jl exists. Maybe a similar trick would work here.


Edit: nope... Doesn't fix it.