We don’t know know what the result of Base.materialize!(::Vector{Float64}, ::Any) could be. Someone could have overloaded Base.materialize!(::Vector{Float64}, ::SomeNewType) to return anything.
Is it reasonable to change the lowering to include a return Y at the end? This should not be breaking, as materialize! being the last step is an implementation detail at best. This can help quite a bit in badly inferred code.
It seems like broadcast!, which is supposed to be equivalent to the in-place dot syntax, handles this by returning the destination array. In the case where it’s a function call in another function, I’m still not entirely sure how the runtime dispatch of broadcast! is inferred properly even when I @noinline it , I thought it would’ve been an unknown call with unknown return type like with materialize!: because the compiler does check the sole method’s return type. You can ruin it by type pirating more applicable methods for the runtime call: for T in (Bool, Float64, Float32, ComplexF64) @eval Base.broadcast!(f::Tf, dest, A1::Vector{Float64}, As::Vararg{$T, N}) where {Tf, N} = $(zero(T)) end # no methods for the Int example.
julia> function test1(a::Vector{Any} = Any[2])
two = a[begin] # what the original code always results in
dest = rand(2)
@noinline broadcast!(+, dest, dest, two)
end
test1 (generic function with 2 methods)
julia> @code_warntype test1(Any[2])
MethodInstance for test1(::Vector{Any})
from test1(a::Vector{Any}) in Main at REPL[7]:1
Arguments
#self#::Core.Const(test1)
a::Vector{Any}
Locals
val::Vector{Float64}
dest::Vector{Float64}
two::Any
Body::Vector{Float64}
1 ─ %1 = Base.firstindex(a)::Core.Const(1)
│ (two = Base.getindex(a, %1))
│ (dest = Main.rand(2))
│ nothing
│ (val = Main.broadcast!(Main.:+, dest, dest, two))
│ nothing
└── return val
compared to
julia> function test2(a::Vector{Any})
two = a[begin] # what the original code always results in
dest = rand(2)
dest .+= two
end
test2 (generic function with 1 method)
julia> @code_warntype test2(Any[2])
MethodInstance for test2(::Vector{Any})
from test2(a::Vector{Any}) in Main at REPL[32]:1
Arguments
#self#::Core.Const(test2)
a::Vector{Any}
Locals
dest::Vector{Float64}
two::Any
Body::Any
1 ─ %1 = Base.firstindex(a)::Core.Const(1)
│ (two = Base.getindex(a, %1))
│ (dest = Main.rand(2))
│ %4 = dest::Vector{Float64}
│ %5 = Base.broadcasted(Main.:+, dest, two)::Any
│ %6 = Base.materialize!(%4, %5)::Any
└── return %6