Example code:
mutable struct Foo{T}
v::Vector{T}
n::Int
# possibly lots more fields, which I don't want
# to have to copy each time with unsafe_{load,store!}
end
function demo()
a = Foo{Int64}([1], 2)
pa = pointer_from_objref(a) # gives me an untyped Ptr{Nothing}
# pa passed on to a C library ...
# ... pa received back through a C callback function
tpa = convert(Ptr{Foo{Int64}}, pa) # C callback function restores type
# tpa[].n += 1 is not allowed
na = unsafe_pointer_to_objref(tpa)
na.n += 1
end
demo() == 3 && @code_warntype demo()
@code_warntype demo()
shows this function to be type unstable, returning ::Any
instead of ::Int64
:
Variables
#self#::Core.Compiler.Const(demo, false)
a::Foo{Int64}
pa::Ptr{Nothing}
tpa::Ptr{Foo{Int64}}
na::Any
Body::Any
1 ─ %1 = Core.apply_type(Main.Foo, Main.Int64)::Core.Compiler.Const(Foo{Int64}, false)
│ %2 = Base.vect(1)::Array{Int64,1}
│ (a = (%1)(%2, 2))
│ (pa = Main.pointer_from_objref(a))
│ %5 = Core.apply_type(Main.Foo, Main.Int64)::Core.Compiler.Const(Foo{Int64}, false)
│ %6 = Core.apply_type(Main.Ptr, %5)::Core.Compiler.Const(Ptr{Foo{Int64}}, false)
│ (tpa = Main.convert(%6, pa))
│ (na = Main.unsafe_pointer_to_objref(tpa))
│ %9 = Base.getproperty(na, :n)::Any
│ %10 = (%9 + 1)::Any
│ Base.setproperty!(na, :n, %10)
└── return %10
with ::Any
highlighted in red. This seems due to the definition in Base
of
unsafe_pointer_to_objref(x::Ptr) = ccall(:jl_value_ptr, Any, (Ptr{Cvoid},), x)
Is is not possible for Base
to implement a method
unsafe_pointer_to_objref(x::Ptr{T})::T
for which the compiler can infer the return type being T
?