@@ -46,6 +46,9 @@ impl const Add for MyInt {
46
46
}
47
47
```
48
48
49
+ You cannot implement both ` const Add ` and ` Add ` for any type, since the ` const Add `
50
+ impl is used as a regular impl outside of const contexts.
51
+
49
52
The const requirement is inferred on all bounds of the impl and its methods,
50
53
so in the following ` H ` is required to have a const impl of ` Hasher ` , so that
51
54
methods on ` state ` are callable.
@@ -102,9 +105,16 @@ bounds for types substituted for `T`.
102
105
103
106
## Drop
104
107
105
- A notable use case of ` impl const ` is defining ` Drop ` impls. If you write
108
+ A notable use case of ` impl const ` is defining ` Drop ` impls.
109
+ Since const evaluation has no side effects, there is no simple example that
110
+ showcases ` const Drop ` in any useful way. Instead we create a ` Drop ` impl that
111
+ has user visible side effects:
106
112
107
113
``` rust
114
+ let x = Cell :: new (42 );
115
+ SomeDropType (& x );
116
+ // x is now 41
117
+
108
118
struct SomeDropType <'a >(& 'a Cell <u32 >);
109
119
impl const Drop for SomeDropType {
110
120
fn drop (& mut self ) {
@@ -113,8 +123,14 @@ impl const Drop for SomeDropType {
113
123
}
114
124
```
115
125
116
- Then you are allowed to actually let a value of ` SomeDropType ` get dropped within a constant
117
- evaluation. This means ` (SomeDropType(&Cell::new(42)), 42).1 ` is now allowed, because we can prove
126
+ You are now allowed to actually let a value of ` SomeDropType ` get dropped within a constant
127
+ evaluation. This means
128
+
129
+ ``` rust
130
+ (SomeDropType (& Cell :: new (42 )), 42 ). 1
131
+ ```
132
+
133
+ is now allowed, because we can prove
118
134
that everything from the creation of the value to the destruction is const evaluable.
119
135
120
136
Note that all fields of types with a ` const Drop ` impl must have ` const Drop ` impls, too, as the
@@ -140,11 +156,24 @@ impl<T: Add> const Add for Foo<T> {
140
156
Foo (self . 0 + other . 0 )
141
157
}
142
158
}
159
+ #[derive(Debug )]
160
+ struct Bar ;
161
+ impl Add for Bar {
162
+ fn add (self , other : Self ) -> Self {
163
+ println! (" hello from the otter side: {:?}" , other );
164
+ self
165
+ }
166
+ }
167
+ impl Neg for Bar {
168
+ fn neg (self ) -> Self {
169
+ self
170
+ }
171
+ }
143
172
```
144
173
145
- allows calling ` Foo(String::from("foo")) + Foo(String::from("bar")) ` even though that is (at the time
146
- of writing this RFC) most definitely not const, because ` String ` only has an ` impl Add for String `
147
- and not an ` impl const Add for String ` . Expressed in some sort of effect system syntax (neither
174
+ allows calling ` Foo(Bar) + Foo(Bar) ` even though that is most definitely not const,
175
+ because ` Bar ` only has an ` impl Add for Bar `
176
+ and not an ` impl const Add for Bar ` . Expressed in some sort of effect system syntax (neither
148
177
effect syntax nor effect semantics are proposed by this RFC, the following is just for demonstration
149
178
purposes):
150
179
@@ -159,25 +188,25 @@ impl<c: constness, T: const(c) Add> const(c) Add for Foo<T> {
159
188
In this scheme on can see that if the ` c ` parameter is set to ` const ` , the ` T ` parameter requires a
160
189
` const Add ` bound, and creates a ` const Add ` impl for ` Foo<T> ` which then has a ` const fn add `
161
190
method. On the other hand, if ` c ` is ` ?const ` , we get a regular impl without any constness anywhere.
162
- Of course for regular impls one can still pass a ` T ` which has a ` const Add ` impl, but that won't
191
+ For regular impls one can still pass a ` T ` which has a ` const Add ` impl, but that won't
163
192
cause any constness for ` Foo<T> ` .
164
193
165
194
This goes in hand with the current scheme for const functions, which may also be called
166
195
at runtime with runtime arguments, but are checked for soundness as if they were called in
167
196
a const context. E.g. the following function may be called as
168
- ` add(String::from("foo"), String::from("bar") ) ` at runtime.
197
+ ` add(Bar, Bar ) ` at runtime.
169
198
170
199
``` rust
171
- const fn add <T : Add > (a : T , b : T ) -> T {
172
- a + b
200
+ const fn add <T : Neg , U : Add < T >> (a : T , b : U ) -> T {
201
+ - a + b
173
202
}
174
203
```
175
204
176
205
Using the same effect syntax from above:
177
206
178
207
``` rust
179
- <c : constness > const (c ) fn add <T : const (c ) Add > (a : T , b : T ) -> T {
180
- a + b
208
+ <c : constness > const (c ) fn add <T : const (c ) Neg , U : const ( c ) Add < T >> (a : T , b : U ) -> T {
209
+ - a + b
181
210
}
182
211
```
183
212
@@ -225,7 +254,7 @@ in an `impl`. This has several uses, most notably
225
254
In order to keep both advantages in the presence of ` impl const ` s, we need a way to declare the
226
255
method default body as being ` const ` . The exact syntax for doing so is left as an open question to
227
256
be decided during the implementation and following final comment period. For now one can add the
228
- ` #[default_method_body_is_const] ` attribute to the method.
257
+ placeholder ` #[default_method_body_is_const] ` attribute to the method.
229
258
230
259
``` rust
231
260
trait Foo {
@@ -286,7 +315,7 @@ but it covers the most common cases. See also the alternatives.
286
315
## Effect system
287
316
288
317
A fully powered effect system can allow us to do fine grained constness propagation
289
- (or no propagation where undesirable). This is way out of scope in the near future
318
+ (or no propagation where undesirable). This is out of scope in the near future
290
319
and this RFC is forward compatible to have its background impl be an effect system.
291
320
292
321
## Fine grained ` const ` annotations
@@ -295,13 +324,13 @@ One could annotate methods instead of impls, allowing just marking some method i
295
324
as const fn. This would require some sort of "const bounds" in generic functions that
296
325
can be applied to specific methods. E.g. ` where <T as Add>::add: const ` or something of
297
326
the sort. This design is more complex than the current one and we'd probably want the
298
- current one as sugar anyway
327
+ current one as sugar anyway.
299
328
300
329
## Require ` const ` bounds everywhere
301
330
302
331
One could require ` const ` on the bounds (e.g. ` T: const Trait ` ) instead of assuming constness for all
303
332
bounds. That design would not be forward compatible to allowing ` const ` trait bounds
304
- on non-const functions, e.g. in
333
+ on non-const functions, e.g. in:
305
334
306
335
``` rust
307
336
fn foo <T : const Bar >() -> i32 {
@@ -318,7 +347,7 @@ annotate methods in trait impls, but we would not block calling a function on wh
318
347
generic parameters fulfill some sort of constness rules. Instead we'd catch this during
319
348
const evaluation.
320
349
321
- This is strictly the most powerful and generic variant, but is an enormous backwards compatibility
350
+ This is strictly the least restrictive and generic variant, but is a semver
322
351
hazard as changing a const fn's body to suddenly call a method that it did not before can break
323
352
users of the function.
324
353
@@ -331,7 +360,8 @@ about. Notable mentions (see also the alternatives section):
331
360
* const trait bounds on non-const functions allowing the use of the generic parameter in
332
361
constant expressions in the body of the function or maybe even for array lenghts in the
333
362
signature of the function
334
- * fine grained bounds for single methods and their bounds
363
+ * fine grained bounds for single methods and their bounds (e.g. stating that a single method
364
+ is const)
335
365
336
366
It might also be desirable to make the automatic ` Fn* ` impls on function types and pointers ` const ` .
337
367
This change should probably go in hand with allowing ` const fn ` pointers on const functions
@@ -483,17 +513,18 @@ themselves known:
483
513
484
514
is already legal in Rust today , even though the `F ` doesn 't need to be a `const ` function .
485
515
486
- 2 . Opt out bounds are ugly
487
-
488
- I don 't think it 's either intuitive nor readable to write the following
516
+ 2 . Opt out bounds might seem unintuitive ?
489
517
490
518
```rust
491
519
const fn foo (f : ? const fn () -> i32 ) -> i32 {
492
520
// not allowed to call `f` here, because we can't guarantee that it points to a `const fn`
493
521
}
522
+ const fn foo (f : fn () -> i32 ) -> i32 {
523
+ f ()
524
+ }
494
525
```
495
526
496
- Thus it seems useful to prefix function pointers to `const ` functions with `const `:
527
+ Alternatively one can prefix function pointers to `const ` functions with `const `:
497
528
498
529
```rust
499
530
const fn foo (f : const fn () -> i32 ) -> i32 {
@@ -530,8 +561,42 @@ fn foo<T: const Bar>() -> i32 {
530
561
Which, once ` const ` items and array lengths inside of functions can make use of the generics of
531
562
the function, would allow the above function to actually exist.
532
563
564
+ ## ` dyn Trait `
565
+
566
+ A natural extension to this RFC is to allow
567
+
568
+ ``` rust
569
+ const fn foo (bar : & dyn Trait ) -> SomeType {
570
+ bar . some_method ()
571
+ }
572
+ ```
573
+
574
+ with an opt out via ` ?const `
575
+
576
+ ``` rust
577
+ const fn foo (bar : & dyn ? const Trait ) -> SomeType {
578
+ bar . some_method () // ERROR
579
+ }
580
+ ```
581
+
533
582
# Unresolved questions
534
583
[ unresolved-questions ] : #unresolved-questions
535
584
536
585
The syntax for specifying that a trait method's default body is ` const ` is left unspecified and uses
537
586
the ` #[default_method_body_is_const] ` attribute as the placeholder syntax.
587
+
588
+ ## Implied bounds
589
+
590
+ Assuming we have implied bounds on functions or impl blocks, will the following compile?
591
+
592
+ ``` rust
593
+ struct Foo <T : Add > {
594
+ t : T ,
595
+ u : u32 ,
596
+ }
597
+
598
+ /// T has implied bound `Add`, but is that `const Add` or `?const Add` or `!const Add`?
599
+ const fn foo <T >(foo : Foo <T >, bar : Foo <T >) -> T {
600
+ foo . t + bar . t
601
+ }
602
+ ```
0 commit comments