I see this a lot in Rust code. Here are a few examples from the standard library:
impl<T> const Default for Option<T> {...}
impl const From<char> for u64 {...}
What is impl const
?
If you run the code:
trait Example {}
impl const Example for u8 {}
You get an error message that points you in the right direction:
error[E0658]: const trait impls are experimental
--> src/lib.rs:3:6
|
3 | impl const Example for u8 {}
| ^^^^^
|
= note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
Issue 67792 is the tracking issue for RFC 2632 — Calling methods on generic parameters of const fns.
This is an unstable syntax that allows defining traits that can be used in a const
context. It's paired with the equally unstable ~const
syntax that can be used in trait bounds:
// 1.59.0-nightly (2021-12-20 23f69235ad2eb9b44ac1)
#![feature(const_fn_trait_bound)]
#![feature(const_trait_impl)]
trait Example {
fn usage(&self) -> Self;
}
impl const Example for u8 {
fn usage(&self) -> Self {
42
}
}
const fn demo<T: ~const Example>(v: &T) -> T {
v.usage()
}
const VALUE: u8 = demo(&1);
fn main() {
dbg!(VALUE);
}
I accepted Shepmaster's answer, but as this question has been gaining popularity, I thought it might also be useful to add some more insight into those const
rules. I'll use the same example provided by Shepmaster. A few things have changed since he posted it, so I've updated the example with comments.
// 1.68.0-nightly (2022-12-11 bdb07a8ec8e77aa10fb8)
//#![feature(const_fn_trait_bound)] <-- Not needed since Rust 1.61
#![feature(const_trait_impl)] // const trait impls are (still) experimental/unstable
#[const_trait] // This is needed now
trait Example {
fn usage(&self) -> Self;
}
impl const Example for u8 {
fn usage(&self) -> Self {
42
}
}
const fn demo<T: ~const Example>(v: &T) -> T {
v.usage()
}
const VALUE: u8 = demo(&1);
fn main() {
dbg!(VALUE);
}
Let's say we started with no other const
s apart from const VALUE
. If fn demo
were not const fn demo
, we would have gotten this error:
error[E0015]: cannot call non-const fn `demo::<u8>` in constants
So far, that has nothing to do with traits per se. But if we just changed fn demo
to const fn demo
, the compiler would complain with:
error[E0277]: the trait bound `T: ~const Example` is not satisfied
note: the trait `Example` is implemented for `T`, but that implementation is not `const`
and
error[E0015]: cannot call non-const fn `<T as Example>::usage` in constant functions
note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
Just adding a trait bound ~const
to Example
wouldn't do:
error: ~const can only be applied to `#[const_trait]` traits
We need to add #[const_trait]
to trait Example
and change impl Example
to impl const Example
.
#[const_trait]
was added recently and is now required on Trait
for impl const Trait
.
Some more info by the compiler when #[const_trait]
is missing:
error: const `impl` for trait `Example` which is not marked with `#[const_trait]`
|
7 | trait Example {
| - help: mark `Example` as const: `#[const_trait]`
...
11 | impl const Example for u8 {
| ^^^^^^^
|
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
= note: adding a non-const method body in the future would be a breaking change
As explained here, the rational behind requiring #[const_trait]
on trait Example
when we have impl const Example
is that that prevents adding a new default method to Example
from becoming a breaking change (as it could be a non-const fn).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With