I tried to dig deeper and indeed LightSumTypes.jl fails in the general case, sorry for having been wrong, e.g. I think this is a total failure in terms of inference:
julia> using LightSumTypes
julia> @sumtype X(Bool, Int, Vector{Bool}, Vector{Int})
julia> xs = [X([1,2]), X(true)]
julia> Base.sum(x::X) = sum(variant(x));
julia> @code_warntype sum.(xs)
MethodInstance for (::var"##dotfunction#230#3")(::Vector{X})
from (::var"##dotfunction#230#3")(x1) @ Main none:0
Arguments
#self#::Core.Const(var"##dotfunction#230#3"())
x1::Vector{X}
Body::AbstractVector
1 ─ %1 = Base.broadcasted(Main.sum, x1)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(sum), Tuple{Vector{X}}}
│ %2 = Base.materialize(%1)::AbstractVector
└── return %2
LightSumTypes.jl works efficiently when working with fields of structs, but I actually didn’t try to work something out for this use case, and I’m afraid that currently it doesn’t work as expected.
Though, I think we can easily patch this with adding to the source code something like:
function apply(f::Function, sumt)
v = $LightSumTypes.unwrap(sumt)
$(branchs(variants, :(return f(v))))
end
with this @code_warntype returns
julia> Base.sum(x::X) = apply(sum, x);
julia> @code_warntype sum.(xs)
MethodInstance for (::var"##dotfunction#230#1")(::typeof(sum), ::Vector{X})
from (::var"##dotfunction#230#1")(x1, x2) @ Main none:0
Arguments
#self#::Core.Const(var"##dotfunction#230#1"())
x1::Core.Const(sum)
x2::Vector{X}
Body::Vector{Int64}
1 ─ %1 = Base.broadcasted(Main.apply, x1, x2)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(apply), Tuple{Base.RefValue{typeof(sum)}, Vector{X}}}
│ %2 = Base.materialize(%1)::Vector{Int64}
└── return %2
I don’t have much time at the moment, but if someone wants to help by implementing a more structured version of this idea, I would be glad to include something like this
Though it will be harder for functions which require multiple inputs, some of which are not sumtypes. We are basically bound to try to pattern match automatically. Maybe possible with generated functions?