Invalid JETLS warning

The following code:

Base.@kwdef mutable struct SysState{P}
    acc::Float64 = 0
    "vector of particle positions in x [m]"
    X::MVector{P, Float64} = zeros(P)
end

gives the warning:

`KiteUtils.P` is not defined

I think this is a bug, but the issue I created was closed: Invalid warning about type parameter · Issue #412 · aviatesk/JETLS.jl · GitHub

I don’t understand why. Is there a bug in the Base.@kwdef macro?

It looks like that:

julia> ex = @macroexpand Base.@kwdef mutable struct SysState{P}
           acc::Float64 = 0
           "vector of particle positions in x [m]"
           X::Vector{P} = zeros(P)
       end
quote
    #= util.jl:630 =#
    begin
        $(Expr(:meta, :doc))
        mutable struct SysState{P}
            #= REPL[4]:2 =#
            acc::Float64
            #= REPL[4]:3 =#
            "vector of particle positions in x [m]"
            X::Vector{P}
        end
    end
    #= util.jl:631 =#
    begin
        function SysState(; acc = 0, X = zeros(P))
            #= REPL[4]:1 =#
            SysState(acc, X)
        end
        function SysState{P}(; acc = 0, X = zeros(P)) where P
            #= REPL[4]:1 =#
            SysState{P}(acc, X)
        end
    end
end

Any comments?

I think I get the warning, because SysState() is not defined. But shouldn’t it be allowed to define a type that requires a type parameter?

This method is trying to access a global P, unrelated to the P of the SysState{P} struct block. This would be a lot easier to fix if the struct’s field annotations were carried over to the generated methods, but introducing that would be a breaking restriction.

at-kwdef generates incorrect generic constructors for structs with type parameters · Issue #54601 · JuliaLang/julia

This issue also mentions a failure of field type conversion that I’m pretty sure you’d also run into if the first issue were evaded. SysState{P} gets a method with the unannotated positional arguments that tries to convert all the fields, but SysState does not.

Thank you for providing a link to this issue in Julia. But is there any known workaround?

I didn’t think through my last comment, it would actually make no sense to annotate X there to infer P from a default value with an unknown P. In other words, if you don’t specify P with an explicit parameter or an explicit X value, a SysState call has no reasonable way to infer P. So, function SysState(; acc = 0, X) would be a reasonable fix, no breaking changes needed. Extra annotations could only help if P were inferred from another field annotated with P and its default value were either absent or not using the P typevar, but that’s too weirdly indirect a way to specify P.

The field type conversion problem would still stop this example though. That’s not an issue with @kwdef anymore, just a question of whether we want more default outer constructors to handle type conversions for parametric types.