Re: [PATCH 2/2] rust: num: add `cv!` macro to create values from constant expressions

From: Gary Guo

Date: Fri Aug 28 2026 - 10:19:00 EST


On Fri Aug 28, 2026 at 1:03 PM BST, Gary Guo wrote:
> Currently, constructing a `NonZero` or `Bounded` from a constant is
> verbose. The former would require `const { NonZero::new(...).unwrap() }`
> and the latter require turbofish. Similarly, the `num::casts` exposes
> methods that cast numbers using turbofish syntax, which is unergonomic and
> unnecessarily causes the value to flow into the type system, which is very
> restrictive without `generic_const_exprs`.
>
> Implement a macro `cv!` (short for constant value) which converts a const
> integer to types that implements `FromConst` trait and validate them during
> const evaluation.
>
> The usage is of form
>
> cv!(<expression>)
>
> for inferred type and
>
> cv!(<expression> => <type>)
>
> for explicit type specification.
>
> As we do not have const trait implementation yet, dark magic is used. The
> dark magic is documented in the code, but in essence it defines inherent
> `__from_const` impls on types, which can be marked const, and rely on
> Rust's method resolution algorithm to pick the correct function. Multiple
> helpers are defined to aid type inference to work properly.

Here's a generalized version that work for any trait methods (same limitation,
that you cannot use this trick if you have only `T: Trait` instead of a specific
`T`):

// Inference helper.
const fn would_call<T, U, F: FnOnce(T) -> U>(_: T, _: F) -> U {
todo!()
}

// We can have a single helper type for *all* fake const traits, as long as
// method names don't duplicate.
struct Const<T>(T);

impl<T> core::ops::Deref for Const<T> {
type Target = T;

#[inline]
fn deref(&self) -> &T {
&self.0
}
}

// Const call!
macro_rules! cc {
(($e:expr).$ident:ident($($args:tt)*)) => {
if false {
// The normal "runtime" call path for type inference.
would_call($e, |x| x.$ident($($args)*));
} else {
// Dispatch via inherent methods. Type already known with the above
// helper!
// A drawback here is that `$e` -> `&$e` autoref won't work here, as
// `Deref` impl is not const.
Const($e).$ident($($args)*)
}
}
}

// Imagine this being an attribute macro.
macro_rules! const_trait {
(impl const $tr:ident for $ty:ty {
fn $method:ident(self: $self_ty:ty) $body:block
}) => {
impl $tr for $ty {
fn $method(self: $self_ty) {
Const(self).$method()
}
}

impl $ty {
pub const fn $method(self: Const<$self_ty>) $body
}
}
}

struct MyStruct;

trait MyTrait {
fn foo(self: Self);
}

const_trait!{
impl const MyTrait for MyStruct {
fn foo(self: Self) {}
}
}

fn test() {
const {
let x = MyStruct;
// MAGIC!
cc!((x).foo());
}
}