Reputation: 999
This code wouldn't compile, why Rust don't even allow this? It's just simple enum variation test, is there any way to workaround?
#![feature(const_fn)]
struct Test {}
#[derive(PartialEq, Eq, Copy, Clone)]
enum Vk {
BLOCK,
ITEM,
}
trait HasC {
const d: Vk;
}
impl HasC for Test {
const d: Vk = Vk::BLOCK;
}
const fn try_use_enum_in_const_fn<T: HasC>() -> bool {
const a: Vk = Vk::BLOCK;
T::d == a
}
fn main() {
println!("{}", try_use_enum_in_const_fn::<Test>());
}
It gets error
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> src/main.rs:21:5
|
21 | T::d == a
| ^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0015`.
Upvotes: 1
Views: 1072
Reputation: 10424
It's just simple enum variation test
Not exactly. You're using ==
which desugars to an application of the PartialEq
method eq
. Since const
trait methods aren't possible yet (and the RFC for them hasn't even been accepted), you can't mark that method as const
, so ==
is unusable in const
functions.
Well ... almost unusable. There are a few exceptions for primitive types. Replace your T::d == a
with 2 == 2
and everything compiles fine. The reason is that equality between certain primitive types (including integers and floats) doesn't use the PartialEq
trait but is implemented more intrinsically. This intrinsic implementation can be used in const
functions.
The most idiomatic solution might be to use a match
or if let
to check an enum variant, but unfortunately, match
doesn't work in const
functions yet either. If you're using nightly (and it appears you are) the feature flag const_if_match
will enable it.
const fn try_use_enum_in_const_fn<T: HasC>() -> bool {
if let Vk::BLOCK = T::d {
true
} else {
false
}
}
It's somewhat of a hack, but on stable currently, you can reduce an enum variant check to equality between primitive integer types and take advantage of the compiler magic mentioned above. When none of the enum variants have data attached to them, they can be cast to primitive integer types. The first variant is by default 0, then 1 etc., though this can be overridden. (Though I'm sure you're aware that what you're doing with traits here isn't stable yet - so this won't work entirely on stable).
const fn try_use_enum_in_const_fn<T: HasC>() -> bool {
const a: Vk = Vk::BLOCK;
(T::d as isize) == (a as isize)
}
Upvotes: 4