Const functions have various restrictions to make sure that they can be evaluated at compile-time. It is, for example, not possible to write a random number generator as a const function. Calling a const function at compile-time will always yield the same result as calling it at runtime, even when called multiple times. There's one exception to this rule: if you are doing complex floating point operations in extreme situations, then you might get (very slightly) different results. It is advisable to not make array lengths and enum discriminants depend on floating point computations.
(emphasis, mine)
What sort of use case do you have in mind? Your example could be implemented without needing const functions, so I'm guessing there is some other scenario you had to simplify.
Not currently, and fundamentally not during constant evaluation. It's an important quality that if you say ConstGeneric<{inc()}> in one place and I say ConstGeneric<{inc()}> somewhere else, we must get the same result for the type system to be sound.
However, you mustn't rely on const fn implying some form of purity. It's reasonably likely that the behavior of const fn will be allowed to diverge between compile time evaluation and runtime evaluation, including the potential for runtime evaluation to be properly impure. It's already the case that some unstable const fn have runtime behavior which refines the compile time behavior, e.g. guaranteed_eq and align_offset.
But it also depends on your definition of purity. It's currently disallowed to have cost &mut or const refs to cells, but these are both things which we'd like to support in the future.
Hm, that's unfortunate. Actually my use case is exactly this, generating incrementing numbers at compile time. I'm working on an alternative to ghost-cell that instead uses const generics, and it would be much better for the ergonomics of the crate if I could generate const usizes at compile time like this:
let t1 = gen_token(); //Token::<0>
let t2 = gen_token(); //token::<1>
I'd even be happy to do this in the form of a proc-macro but, as far as I'm aware, there's no way for proc-macros to know what "position" they've been called in.
You could parse the debug output of a span, which includes the line and column of the token. Doing so is (obviously) not guaranteed behavior, and can change at any time for any reason. I don't particularly advise you do this, but if it's absolutely necessary…
let (t1, t2, t3, t4);
let mut first = true;
for _ in 0..2 {
let a1 = gen_token!();
let a2 = gen_token!();
if first {
t1 = a1;
t2 = a2;
} else {
t3 = a1;
t4 = a2;
}
first = false;
}
dbg!(t1, t2, t3, t4);
do you want 0, 1, 2, 3 or 0, 1, 0, 1? The former is strictly impossible (some code always evaluates to the same type); the latter is at least probabilistically possible via procedural macro powered const-random techniques (though it's still only probabilistic and duplicates are impossible to prevent because of separate compilation).