From 3a77fc6eaee8b5426b870204b801baa21d327dd1 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Tue, 11 Mar 2025 13:00:18 -0700 Subject: [PATCH] [macros] Support const fns with bounds on MSRV gherrit-pr-id: Icdb256acfdb274f34312cf5b216a02ca426338a1 --- src/util/macros.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/util/macros.rs b/src/util/macros.rs index cdd32e18d6..31337a0066 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -802,3 +802,83 @@ macro_rules! impl_size_eq { }; }; } + +macro_rules! const_fn { + ( + $vis:vis $name:ident $(< $($tyvar:ident),* >)? + ( $($arg:ident: $argty:ty),* ) -> $retty:ty + $( + where $($wheretyvar:ident: $wherebound:path,)* + )? + $body:block + ) => { + #[allow(non_camel_case_types)] + $vis trait $name $(< $($tyvar),* >)? + where Self: crate::util::macros::HasArgs<($($argty,)*), Args = ($($argty,)*)>, + $( + $($wheretyvar: $wherebound),* + )? + { + const ARGS: Self::Args; + + const __RETURN: $retty = { + let ($($arg),*) = Self::ARGS; + loop { + break $body; + } + }; + } + }; +} + +macro_rules! call_const_fn { + ( + $name:ident $(:: $names:ident)* $(:: < $($ty:ty),* >)? ($($arg:expr),*) + ) => { + { + enum Call {} + + impl $name $(:: $names)* $(< $($ty),* >)? for Call { + const ARGS: Self::Args = ($($arg,)*); + } + + )?>::__RETURN + } + }; +} + +// Used in the implementation of `const_fn!`. +pub(crate) trait HasArgs { + type Args; +} + +impl HasArgs for T { + type Args = A; +} + +mod tests { + #[test] + fn test_const_fn() { + trait Foo { + const N: usize; + } + + impl Foo for () { + const N: usize = 5; + } + + const_fn!(foobar(_t: T, n: usize) -> usize + where + T: Foo, + T: Copy, + { + T::N * n + }); + + const BLAH: usize = call_const_fn!(foobar::<()>((), 4)); + + const _: () = { + static_assert!(=> BLAH == 20); + }; + } +}