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
+94-20Lines changed: 94 additions & 20 deletions
Original file line number
Diff line number
Diff line change
@@ -151,12 +151,13 @@ Any item that can have trait bounds can also have `const Trait` bounds.
151
151
152
152
Examples:
153
153
154
-
*`T: const Trait`, requiring any type that `T` is instantiated with to have a const trait impl.
155
-
*`dyn const Trait`, requiring any type that is unsized to this dyn trait to have a const trait impl.
156
-
* These are not part of this RFC because they require `const fn` function pointers. See [the Future Possibilities section](#future-possibilities).
154
+
*`T: const Trait`, requiring any type that `T` is instantiated with to have a const trait impl for `Trait`.
155
+
*`dyn const Trait`, requiring any type that is unsized to this dyn trait to have a const trait impl for `Trait`.
156
+
* These are not part of this RFC because they require `const` function pointers. See [the Future Possibilities section](#future-possibilities).
157
157
*`impl const Trait` (in all positions).
158
-
* These are not part of this RFC because they require `const fn` function pointers. See [the Future Possibilities section](#future-possibilities).
158
+
* These are not part of this RFC because they require `const` function pointers. See [the Future Possibilities section](#future-possibilities).
159
159
*`trait Foo: const Bar {}`, requiring every type that has an impl for `Foo` (even a non-const one), to also have a const trait impl for `Bar`.
160
+
*`trait Foo { type Bar: const Trait; }`, requiring all the impls to provide a type for `Bar` that has a const trait impl for `Trait`
160
161
161
162
Such an impl allows you to use the type that is bound within a const block or any other const context, because we know that the type has a const trait impl and thus
162
163
must be executable at compile time. The following function will invoke the `Default` impl of a type at compile time and store the result in a constant. Then it returns that constant instead of computing the value every time.
`~const` is derived from "approximately", meaning "conditionally" in this context, or specifically "const impl required if called in const context".
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.
216
+
It is the opposite of `?` (prexisting for `?Sized` bounds), which also means "conditionally", but from the other direction: `?const`
217
+
(not proposed here, see [this alternatives section](#make-all-const-fn-arguments-const-trait-by-default-and-require-an-opt-out-const-trait) for why it was rejected)
218
+
would mean "no const impl required, even if called in const context".
217
219
218
220
### Const fn
219
221
@@ -251,6 +253,33 @@ You first figure out which method you're calling, then you check its bounds.
251
253
Otherwise it would at least seem like we'd have to allow some SFINAE or method overloading style things,
252
254
which we definitely do not support and have historically rejected over and over again.
253
255
256
+
### conditionally const trait impls
257
+
258
+
`const` trait impls for generic types work similarly to generic `const fn`.
259
+
Any `impl const Trait for Type` is allowed to have `~const` trait bounds.
See [this playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=313a38ef5c36b2ddf489f74167c1ac8a) for an example that works on nightly today.
254
283
255
284
### `~const Destruct` trait
256
285
@@ -339,15 +368,21 @@ These `const` or `~const` trait bounds desugar to normal trait bounds without mo
339
368
340
369
A much more detailed explanation can be found in https://hackmd.io/@compiler-errors/r12zoixg1l#What-now
341
370
371
+
372
+
In contrast to other keywords like `unsafe` or `async` (that give you raw pointer derefs or `await` calls respectively),
373
+
the `const` keyword on functions or blocks restricts what you can do within those functions or blocks.
374
+
Thus the compiler historically used `host` as the internal inverse representation of `const` and `~const` bounds.
375
+
342
376
We generate a `ClauseKind::HostEffect` for every `const` or `~const` bound.
343
377
To mirror how some effectful languages represent such effects,
344
-
I'm going to use `<Type as Trait>::k#host` to allow setting whether the `host` effect is "const" (disabled) or "conditionally" (generic).
345
-
This is not comparable with other associated bounds like type bounds or const bounds, as the values the associated host effect can
346
-
take do neither have a usual hierarchy nor a concrete single value we can compare due to the following handling of those bounds:
378
+
I'm going to use `<Type as Trait>::k#constness` to allow setting whether the `constness` effect is "const" (disabled) or "conditionally" (generic).
379
+
This is not comparable with other associated bounds like type bounds or const bounds, as the values the associated constness effect can
380
+
take do neither have a usual hierarchy of trait bounds or subtyping nor a concrete single value we can compare due to the following handling of those bounds:
347
381
348
-
* There is no "always" (enabled), as that is just the lack of a host effect, meaning no `<Type as Trait>::k#host` bound at all.
382
+
* There is no "disabled", as that is just the lack of a constness effect, meaning no `<Type as Trait>::k#constness` bound at all.
349
383
* In contrast to other effect systems, we do not track the effect as a true generic parameter in the type system,
350
-
but instead just ignore all `Conditionally` bounds in host environments and treat them as `Const` in const environments.
384
+
but instead explicitly convert all requirements of `Conditionally` bounds in always-const environments to `Const`.
385
+
* in other words: calling a `const fn<T: ~const Trait>()` in a const item or const block requires proving that the type used for `T` is `const`, as `~const` can't refer to any conditionally const bound like it can within other const fns.
351
386
352
387
While this could be modelled with generic parameters in the type system, that:
353
388
@@ -373,7 +408,7 @@ desugars to
373
408
fncompile_time_default<T>() ->T
374
409
where
375
410
T:Default,
376
-
<TasDefault>::k#host=Const,
411
+
<TasDefault>::k#constness=Const,
377
412
{
378
413
const { T::default() }
379
414
}
@@ -393,7 +428,7 @@ desugars to
393
428
constfndefault<T>() ->T
394
429
where
395
430
T:Default,
396
-
<TasDefault>::k#host=Conditionally,
431
+
<TasDefault>::k#constness=Conditionally,
397
432
{
398
433
T::default()
399
434
}
@@ -441,6 +476,10 @@ previous rule "adding a new method is not a breaking change if it has a default
441
476
442
477
### `~const Destruct` super trait
443
478
479
+
The `Destruct` marker trait is used to name the previously unnameable drop glue that every type has.
480
+
It has no methods, as drop glue is handled entirely by the compiler,
481
+
but in theory drop glue could become something one can explicitly call without having to resort to extracting the drop glue function pointer from a `dyn Trait`.
482
+
444
483
Traits that have `self` (by ownership) methods, will almost always drop the `self` in these methods' bodies unless they are simple wrappers that just forward to the generic parameters' bounds.
445
484
446
485
The following never drops `T`, because it's the job of `<T as Add>` to handle dropping the values.
@@ -449,7 +488,7 @@ The following never drops `T`, because it's the job of `<T as Add>` to handle dr
0 commit comments