The function cat
seems to internally use cat_t
. The definition of cat_t
that is used in my case is
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
However, for some reason, the function _cat_t
seems type-stable while cat_t
isn’t.
julia> f(a...) = Base._cat_t((1,2), Float64, a...)
f (generic function with 1 method)
julia> @code_warntype f(ones(2,2))
MethodInstance for f(::Matrix{Float64})
from f(a...) in Main at REPL[1]:1
Arguments
#self#::Core.Const(f)
a::Tuple{Matrix{Float64}}
Body::Matrix{Float64}
1 ─ %1 = Base._cat_t::Core.Const(Base._cat_t)
│ %2 = Core.tuple(1, 2)::Core.Const((1, 2))
│ %3 = Core.tuple(%2, Main.Float64)::Core.Const(((1, 2), Float64))
│ %4 = Core._apply_iterate(Base.iterate, %1, %3, a)::Matrix{Float64}
└── return %4
julia> f(a...) = Base.cat_t(Float64, a..., dims=(1,2))
f (generic function with 1 method)
julia> @code_warntype f(ones(2,2))
MethodInstance for f(::Matrix{Float64})
from f(a...) in Main at REPL[3]:1
Arguments
#self#::Core.Const(f)
a::Tuple{Matrix{Float64}}
Body::Any
1 ─ %1 = (:dims,)::Core.Const((:dims,))
│ %2 = Core.apply_type(Core.NamedTuple, %1)::Core.Const(NamedTuple{(:dims,)})
│ %3 = Core.tuple(1, 2)::Core.Const((1, 2))
│ %4 = Core.tuple(%3)::Core.Const(((1, 2),))
│ %5 = (%2)(%4)::Core.Const((dims = (1, 2),))
│ %6 = Base.cat_t::Core.Const(Base.cat_t)
│ %7 = Core.kwfunc(%6)::Core.Const(Base.var"#cat_t##kw"())
│ %8 = Base.cat_t::Core.Const(Base.cat_t)
│ %9 = Core.tuple(%5, %8, Main.Float64)::Core.Const(((dims = (1, 2),), Base.cat_t, Float64))
│ %10 = Core._apply_iterate(Base.iterate, %7, %9, a)::Any
└── return %10
Perhaps the keyword argument isn’t being constant-propagated (I don’t know the internals of how this works). Could someone who is more familiar with how this works explain why cat_t
isn’t type-stable, and if there is a way to get it to infer the return type correctly?
This is on nightly.
julia> VERSION
v"1.8.0-DEV.1060"