You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: text/0000-const-trait-impls.md
+74-2
Original file line number
Diff line number
Diff line change
@@ -132,6 +132,8 @@ Impls can now rely on the default methods being const, too, and don't need to ov
132
132
We may add an attribute later to allow you to mark individual trait methods as not-const so that when creating a const trait, one can
133
133
add (defaulted or not) methods that cannot be used in const contexts.
134
134
135
+
It is possible to split up a trait into the const an non-const parts as discussed [here](#cant-have-const-methods-and-nonconst-methods-on-the-same-trait).
136
+
135
137
All default method bodies of const trait declarations are [const contexts](https://doc.rust-lang.org/reference/const_eval.html#const-context).
`~const` is derived from "approximately", meaning "conditionally" in this context, or specifically "const impl required if called in const context".
213
215
It is the opposite of `?` (prexisting for `?Sized` bounds), which also means "conditionally", but from the other direction: `?const` (not proposed here, see the alternatives section for why it was rejected) would mean "no const impl required, even if called in const context".
216
+
See [this alternatives section](#make-all-const-fn-arguments-const-trait-by-default-and-require-an-opt-out-const-trait) for an explanation of why we do not use a `?const` scheme.
217
+
218
+
### Const fn
219
+
220
+
`const` fn have always been and will stay "always const" functions.
221
+
222
+
It may appear that a function is suddenly "not a const fn" if it gets passed a type that doesn't satisfy
223
+
the constness of the corresponding trait bound. E.g.
constBAR:Foo=bar(Foo); // ERROR: `Foo`'s `Clone` impl is not for `const Clone`.
236
+
```
237
+
238
+
But `bar` is still a `const` fn and you can call it from a const context, it will just fail some trait bounds. This is no different from
239
+
240
+
```rust
241
+
constfndup<T:Copy>(a:T) -> (T, T) {(a, a)}
242
+
constFOO: (String, String) =dup(String::new());
243
+
```
244
+
245
+
Here `dup` is always const fn, you'll just get a trait bound failure if the type you pass isn't `Copy`.
246
+
247
+
This may seem like language lawyering, but that's how the impl works and how we should be talking about it.
248
+
249
+
It's actually important for inference and method resolution in the nonconst world today.
250
+
You first figure out which method you're calling, then you check its bounds.
251
+
Otherwise it would at least seem like we'd have to allow some SFINAE or method overloading style things,
252
+
which we definitely do not support and have historically rejected over and over again.
253
+
214
254
215
255
### `~const Destruct` trait
216
256
@@ -237,6 +277,19 @@ The `Destruct` trait is a bound for whether a type has drop glue. This is trival
237
277
`~const Destruct` trait bounds are satsifed only if the type has a `const Drop` impl or all of the types of its components
238
278
are `~const Destruct`.
239
279
280
+
While this means that it's a breaking change to add a type with a non-const `Drop` impl to a type,
281
+
that's already true and nothing new:
282
+
283
+
```rust
284
+
pubstructS {
285
+
x:u8,
286
+
y:Box<()>, // adding this field breaks code.
287
+
}
288
+
289
+
constfnf(_:S) {}
290
+
//~^ ERROR destructor of `S` cannot be evaluated at compile-time
291
+
```
292
+
240
293
## Trivially enabled features
241
294
242
295
You can use `==` operators on most types from libstd from within const contexts.
@@ -554,6 +607,14 @@ Note that it may frequently be that such a trait should have been split even wit
554
607
555
608
It may seem tempting to use `const fn foo<T: const Trait>` to mean what in this RFC is `~const Trait`, and then add new syntax for bounds that allow using trait methods in const blocks.
556
609
610
+
Examples of possible always const syntax:
611
+
612
+
*`=const Trait`
613
+
*`const const Trait` (lol)
614
+
*`const(always) Trait` (`pub` like)
615
+
*`const<true> Trait` (effect generic like)
616
+
*`const! Trait`
617
+
557
618
## use `Trait<const>` or `Trait<bikeshed#effect: const>` instead of `const Trait`
558
619
559
620
To avoid new syntax before paths referring to traits, we could treat the constness as a generic parameter or an associated type.
@@ -608,6 +669,8 @@ for when a trait bound is only used for its associated types and consts.
608
669
This requires a new `~const fn` syntax (sigils or syntax bikesheddable), as the existing `const fn` already has trait bounds that
609
670
do not require const trait impls even if used in const contexts.
610
671
672
+
An example from libstd today is [the impl block of Vec::new](https://github.com/rust-lang/rust/blob/1ab85fbd7474e8ce84d5283548f21472860de3e2/library/alloc/src/vec/mod.rs#L406) which has an implicit `A: Allocator` bound from [the type definition](https://github.com/rust-lang/rust/blob/1ab85fbd7474e8ce84d5283548f21472860de3e2/library/alloc/src/vec/mod.rs#L397).
673
+
611
674
A full example how how things would look then
612
675
613
676
```rust
@@ -638,8 +701,17 @@ const fn foo<T: Foo>() {
638
701
compiles today, and allows all types that implement `Foo`, irrespective of the constness of the impl.
639
702
With the opt-out scheme that would still compile, but suddenly require callers to provide a const impl.
640
703
641
-
The safe default (and the one folks are used to for a few years now), is that trait bounds just work, you just
642
-
can't call methods on them. To get more capabilities, you add more syntax. Thus the opt-out approach was not taken.
704
+
The safe default (and the one folks are used to for a few years now on stable), is that trait bounds just work, you just
705
+
can't call methods on them.
706
+
This is both useful in
707
+
708
+
* nudging function authors to using the minimal necessary bounds to get their function
709
+
body to compile and thus requiring as little as possible from their callers,
710
+
* ensuring our implementation is correct by default.
711
+
712
+
The implementation correctness argument is partially due to our history with `?const` (see https://github.com/rust-lang/rust/issues/83452 for where we got it wrong and thus decided to stop using opt-out), and partially with our history with `?` bounds not being great either (https://github.com/rust-lang/rust/issues/135229, https://github.com/rust-lang/rust/pull/132209). An opt-in is much easier to make sound and keep sound.
713
+
714
+
To get more capabilities, you add more syntax. Thus the opt-out approach was not taken.
0 commit comments