It’s often wise to explicitly specialize on any inner-loop function passed as an argument, and this resolves issue 3:
function splatting_fnfill_nd!(A::AbstractArray{<:Any,K}, f::F, D::Int) where {K, F}
for I ∈ CartesianIndices(ntuple(_ -> D, Val(K)))
A[I] = f(Tuple(I)...)
end
return A
end
julia> let buf = MMatrix{3,3,Bool}(undef)
result = @btime splatting_fnfill_nd!($buf, kron2, 3)
@assert result == I[1:3, 1:3]
println()
@code_warntype splatting_fnfill_nd!(buf, kron2, 3)
end;
4.900 ns (0 allocations: 0 bytes)