I’m having a bit of a weird problem with Cassette when trying to overdub isa , as the result appears to change based on the sequence of calls despite no explicit state being shared between the calls. The example
using Cassette
Cassette.@context Ctx
typ = Tuple{P} where P <: Int
a = Cassette.overdub(Ctx(), isa, typ, DataType)
b = Cassette.overdub(Ctx(), isa, typ.body, DataType)
println("false: $a true: $b")
produces false: false true: false
despite the expected result being false: false true: true
. If a is replaced by a constant, then b is correct (is true); if we invoke isa with Cassette.fallback it works, and if we replace the definition of Cassette.call with one that calls jl_isa directly then it works. For example, adding
function Cassette.call(ctx::Cassette.Context{Cassette.nametype(Ctx),M,Nothing,P,B,H} where H<:Union{Cassette.DisableHooks, Nothing} where B<:Union{Nothing, IdDict{Module,Dict{Symbol,Cassette.BindingMeta}}} where P<:Cassette.AbstractPass where M, ::typeof(isa), a, b::Type)
return ccall(:jl_isa, Cint, (Any, Any), a, b) == 1
end
in between the definition of Ctx and the calls to overdub fixes the problem.
I suspect that the proximal cause of the issue is something to do with the unbound type variable in typ.body
causing the second invocation to call the older (yet still type-specialized) version of isa
, as when you attempt to identify the specialization that is called specifically reflection yells at you because it is a non-leaf-type. However, I haven’t been able to reproduce this in other generated methods, so am at something of a loose end as to where to look next.