Closed
Description
Following from this discussion on the discourse
A summary of the problem is:
# The following works fine:
mt = MyType{Int32,CTable(16)}()
# Define convenience ctor:
MyType{T}() where {T} = MyType{T,CTable(16)}()
# This throws a weird error:
MType{Int32}()
Here is a full minimal working example of the problem:
struct CTable
t::Ptr{Float64}
function CTable(n)
# In practice t is received from the C program
t = @ccall malloc(n::Csize_t)::Ptr{Float64}
return new(t)
end
end
mutable struct MyType{T,Table}
arr::Ptr{T}
function MyType{T,Table}() where {T,Table}
arr = @ccall jl_malloc(10::Csize_t)::Ptr{T}
m = new{T,Table}(arr)
f(m) = @ccall jl_free(m.arr::Ptr{Cvoid})::Cvoid
finalizer(f, m)
return m
end
end
# The following works fine:
mt = MyType{Int32,CTable(16)}()
# However this convenience constructor breaks the code:
MyType{T}() where {T} = MyType{T,CTable(16)}()
MyType{Int32}() # Error!!!
#=
ERROR: ccall return type Ptr should have an element type (not Ptr{<:T})
Stacktrace:
[1] MyType
@ ./REPL[2]:5 [inlined]
[2] (MyType{Int32})()
@ Main ./REPL[4]:1
[3] top-level scope
@ REPL[6]:1
=#
Note that this works fine if one of the following:
- The type is defined without a second parametric type
Table
- The "convenience ctor" is fully defined separately without calling the inner ctor
@ccall
specifies a return typePtr{Cvoid}
, and thenunsafe_convert
s toPtr{T}
The underlying problem was then found by @Seelengrab as discussed at the end of the discourse post