Noticed this when obsessing over type-stability, wonder if what’s below in the code block is considered as an unexpected behavior.
In short, @code_warntype
is happy with foo(x::Vector{<:Real})
, but mad about bar(; x::Vector{<:Real})
.
(It probably has to do with how keyword arguments are ignored on multi-dispatch, and can be “fixed” by defining as bar(; x::Vector{T}) where {T<:Real}...
.)
julia> function foo(x::Vector{<:Real})
println(x);
end
foo (generic function with 1 method)
julia> function bar(;x::Vector{<:Real})
println(x);
end
bar (generic function with 1 method)
julia> @code_warntype foo([3.])
MethodInstance for foo(::Vector{Float64})
from foo(x::Vector{<:Real}) in Main at REPL[1]:1
Arguments
#self#::Core.Const(foo)
x::Vector{Float64}
Body::Nothing
1 ─ %1 = Main.println(x)::Core.Const(nothing)
└── return %1
julia> @code_warntype bar(x=[3.])
MethodInstance for (::var"#bar##kw")(::NamedTuple{(:x,), Tuple{Vector{Float64}}}, ::typeof(bar))
from (::var"#bar##kw")(::Any, ::typeof(bar)) in Main at REPL[2]:1
Arguments
_::Core.Const(var"#bar##kw"())
@_2::NamedTuple{(:x,), Tuple{Vector{Float64}}}
@_3::Core.Const(bar)
Locals
@_4::TypeVar
@_5::Union{}
x::Vector{Float64}
@_7::Vector{Float64}
Body::Nothing
1 ─ %1 = Base.haskey(@_2, :x)::Core.Const(true)
│ Core.typeassert(%1, Core.Bool)
│ %3 = Base.getindex(@_2, :x)::Vector{Float64}
│ %4 = Core.TypeVar(Symbol("#s3"), Main.Real)::Core.Compiler.PartialTypeVar(var"#s3"<:Real, true, true)
│ (@_4 = %4)
│ %6 = @_4::Core.Compiler.PartialTypeVar(var"#s3"<:Real, true, true)
│ %7 = Core.apply_type(Main.Vector, @_4::Core.Compiler.PartialTypeVar(var"#s3"<:Real, true, true))::**Type{Array{var"#s3"<:Real, 1}}**
│ %8 = Core.UnionAll(%6, %7)::Type{Vector{<:Real}}
│ %9 = (%3 isa %8)::Core.Const(true)
│ Core.typeassert(%9, Core.Bool)
└── goto #3
2 ─ Core.Const(:(Core.TypeVar(Symbol("#s4"), Main.Real)))
│ Core.Const(:(@_5 = %12))
│ Core.Const(:(@_5))
│ Core.Const(:(Core.apply_type(Main.Vector, @_5)))
│ Core.Const(:(Core.UnionAll(%14, %15)))
│ Core.Const(:(%new(Core.TypeError, Symbol("keyword argument"), :x, %16, %3)))
└── Core.Const(:(Core.throw(%17)))
3 ┄ (@_7 = %3)
└── goto #5
4 ─ Core.Const(:(Core.UndefKeywordError(:x)))
└── Core.Const(:(@_7 = Core.throw(%21)))
5 ┄ %23 = @_7::Vector{Float64}
│ (x = %23)
│ %25 = (:x,)::Core.Const((:x,))
│ %26 = Core.apply_type(Core.NamedTuple, %25)::Core.Const(NamedTuple{(:x,)})
│ %27 = Base.structdiff(@_2, %26)::Core.Const(NamedTuple())
│ %28 = Base.pairs(%27)::Core.Const(Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}())
│ %29 = Base.isempty(%28)::Core.Const(true)
│ Core.typeassert(%29, Core.Bool)
└── goto #7
6 ─ Core.Const(:(Base.kwerr(@_2, @_3)))
7 ┄ %33 = Main.:(var"#bar#1")(x, @_3)::Core.Const(nothing)
└── return %33
julia>
Thanks for taking a look into this!