Letâs get back to the original pre-RFC.
Iâm for desugaring the const
parameter directly as a const
generic. In particular the following produces different types is concerning:
fn foo(const n: usize) -> [T; n] { ... }
let a = foo(16); // a has type [T; 16]
let b = foo(32); // b has type [T; 32]
Given the motivation is just to support SIMD, I prefer to heavy scale down the scope to what SIMD needs, and make it behave like a normal function, where the type of foo
must not involve N
(i.e. it canât take [T; N]
as input or return a [T; N]
).
If we want to forward a const parameter, it is unavoidable that functions having a const
parameter must be monomorphized. For instance this AVX instruction is defined as following in clang:
// __m256d _mm256_shuffle_pd(__m256d a, __m256d b, const int mask);
#define _mm256_shuffle_pd(a, b, mask) __extension__ ({ \
(__m256d)__builtin_shufflevector((__v4df)(__m256d)(a), \
(__v4df)(__m256d)(b), \
0 + (((mask) >> 0) & 0x1), \
4 + (((mask) >> 1) & 0x1), \
2 + (((mask) >> 2) & 0x1), \
6 + (((mask) >> 3) & 0x1)); })
Translated to Rust would be:
fn _mm256_shuffle_pd(a: __m256d, b: __m256d, const mask: u8) -> __m256d {
simd_shuffle4(a, b, [
0 + ((mask >> 0) & 1),
4 + ((mask >> 1) & 1),
2 + ((mask >> 2) & 1),
6 + ((mask >> 3) & 1),
]) // <-- the compiler needs to recognize [...] is a constant
}
extern "platform-intrinsic" {
fn simd_shuffle4<T, U>(x: T, y: T, const mask: [u8; 4]) -> U;
// ^~~~~ should `const` be allowed here anyway?
}
The comparison to Swift in the âDrawbacksâ section is unfounded. In Swift T.self
is a runtime value of type T.Type
, and everything done through T.self
is going through the runtime reflection. This is more similar to the Class<T>
object in Java. That is, Swift should not be used as an argument to support or reject passing âtypesâ as a function argument since it is totally irrelevant.
If the point is just to use inference to avoid the turbofish, well this is already supported in stable Rust.
use std::marker::PhantomData;
use std::mem::transmute_copy;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct TypeOf<T: ?Sized>(PhantomData<T>);
trait HasTypeOf {
fn type_of() -> TypeOf<Self> {
TypeOf(PhantomData)
}
}
impl<T: ?Sized> HasTypeOf for T {}
unsafe fn unsafe_bit_cast<T, U>(x: T, _: TypeOf<U>) -> U {
transmute_copy(&x) // (can't use transmute(), size of T and U are unknown)
}
fn main() {
unsafe {
let a = 0x3ff00000_00000000u64;
let b = unsafe_bit_cast(a, f64::type_of()); // <-- look ma, no turbofish
assert_eq!(b, 1.0f64);
}
}