Nice! I’m more than happy to provide a bit of feedback to help make this happen.
For point 1, the key is to lean on constant propagation instead of explicit Val usage. The key test cases, then, are going to be introspecting functions that call eachslice with a constant literal tuple. For example:
julia> f(;dims=()) = dims[1]+dims[2]+dims[3]
f (generic function with 1 method)
julia> g() = f(dims=(1,2,3))
g (generic function with 1 method)
julia> @code_llvm g()
; @ REPL[5]:1 within `g'
define i64 @julia_g_12214() {
top:
ret i64 6
}
For this to work, you need to ensure that f inlines up to the point where you use dims. Now combining this with a more complicated algorithm (point 2) is gonna be tricky. Encoding these literal constants as quickly as possible into a typed tuple is probably going to be your best bet. Unfortunately the naive things with ntuple doesn’t quite do the trick:
julia> f(A;dims) = ntuple(i->i in dims ? (:) : 1, ndims(A))
f (generic function with 1 method)
julia> g(A) = f(A, dims=(2,3))
g (generic function with 1 method)
julia> @code_warntype g(rand(3,4,5))
Body::Tuple{Union{Colon, Int64},Colon,Union{Colon, Int64}}
It’s rather amazing how Julia is able to concretely identify the second element in that tuple, but it’s not quite able to follow in the whole way along all the checks in the tuple. Even more amazing is that this is all happening with the totally generic in(x, itr) definition. Ok, so perhaps that’s the key, let’s try adding some specialized in methods for small tuples:
julia> Base.in(x, ::Tuple{}) = false
Base.in(x, t::Tuple{Any}) = x == t[1]
Base.in(x, t::NTuple{2,Any}) = x == t[1] || x == t[2]
Base.in(x, t::NTuple{3,Any}) = x == t[1] || x == t[2] || x == t[3]
Base.in(x, t::NTuple{4,Any}) = x == t[1] || x in Base.tail(t)
julia> @code_warntype g(rand(3,4,5))
Body::Tuple{Int64,Colon,Colon}
# ...
11 ─ return (1, Colon(), Colon())
Now you can encode your constant literals into a Tuple of either Ints or Colons… and then use that for your type-stable algorithm. To use this “template” tuple to replace an arbitrary tuple of indices, walk through them in sync:
replace_colons(template::Tuple{}, idxs::Tuple{}) = ()
replace_colons(template::Tuple{Int, Vararg{Any}}, idxs::Tuple{Any, Vararg{Any}}) = (idxs[1], replace_colons(tail(template), tail(idxs))...)
replace_colons(template::Tuple{Colon, Vararg{Any}}, idxs::Tuple{Any, Vararg{Any}}) = (:, replace_colons(tail(template), tail(idxs))...)