This works, but since the size is compile time known, I would like to fail at compile time. So I did this nifty trick to make this a compile time assertion:
and this makes the compiler tell me can't use generic parameters from outer function. Why is it that it only gets upset in the constant-evaluated context. This seems like it's a misleading error message because to my mind I have been using the generic parameters from the outer function in the first case as well...
Currently items (like const, static, struct, enum, fn etc etc) are kinda global. Even if you define them inside some scope (like in this case you're defining a const inside the scope of a function) the definition will still be as if you defined it outside, except the name is only visible inside the scope you defined it.
and it's clear here that T and U are not available to the definition of the const.
This doesn't happen with just assert, because it's a statement, not an item.
You can work around this problem by using an associated const because those have access to the generic parameters of the impl, but it's not very intuitive and is a bit boilerplaty:
fn do_magic<T,U>(t: T, u: U) {
struct Helper<A, B>(A, B);
impl<A, B> Helper<A, B> {
// Here A and B are available to the associated const
const ASSERTION: () = assert!(core::mem::size_of::<A>() == core::mem::size_of::<B>());
}
// Force the monomorphization of the constant
let _ = Helper::<T, U>::ASSERTION;
// ...
}
In the future you might be able to make the const directly generic over A and B and then force the monomorphization, which should reduce a bit the boilerplate.