Any computation the type system can do can be used here. As it’s Turing-complete, there’s really no limit. Here’s an implementation of Forth that runs at compile-time on stable, for instance (not mine):
More bending of the rules; a nonterminating FizzBuzz implemenation:
use std::fmt::Debug;
struct ConstMain;
impl Debug for ConstMain {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
let mut x:u64 = 1;
loop {
x += 1;
println!("{}", match x {
fb if fb % 15 == 0 => "FizzBuzz".into(),
f if f % 3 == 0 => "Fizz".into(),
b if b % 5 == 0 => "Buzz".into(),
x => x.to_string()
});
// Comment out for infinite loop
// if x > 200 { std::process::exit(0); }
}
}
}
const
fn main() -> Result<(), ConstMain> {
Err(ConstMain)
}
Nice trick! This way, you can in fact "smuggle" any calculation out of the const fn main(), since they'll be running in the std runtime, which is non-const context.
The challenge was writing a program with a const fn main declaration. I realized that you can have a non-const Debug implementation that will be called after main returns a constant Err(...).