@@ -46,6 +46,9 @@ impl const Add for MyInt {
4646}
4747```
4848
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+
4952The const requirement is inferred on all bounds of the impl and its methods,
5053so in the following ` H ` is required to have a const impl of ` Hasher ` , so that
5154methods on ` state ` are callable.
@@ -102,9 +105,16 @@ bounds for types substituted for `T`.
102105
103106## Drop
104107
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:
106112
107113``` rust
114+ let x = Cell :: new (42 );
115+ SomeDropType (& x );
116+ // x is now 41
117+
108118struct SomeDropType <'a >(& 'a Cell <u32 >);
109119impl const Drop for SomeDropType {
110120 fn drop (& mut self ) {
@@ -113,8 +123,14 @@ impl const Drop for SomeDropType {
113123}
114124```
115125
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
118134that everything from the creation of the value to the destruction is const evaluable.
119135
120136Note 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> {
140156 Foo (self . 0 + other . 0 )
141157 }
142158}
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+ }
143172```
144173
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
148177effect syntax nor effect semantics are proposed by this RFC, the following is just for demonstration
149178purposes):
150179
@@ -159,25 +188,25 @@ impl<c: constness, T: const(c) Add> const(c) Add for Foo<T> {
159188In this scheme on can see that if the ` c ` parameter is set to ` const ` , the ` T ` parameter requires a
160189` const Add ` bound, and creates a ` const Add ` impl for ` Foo<T> ` which then has a ` const fn add `
161190method. 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
163192cause any constness for ` Foo<T> ` .
164193
165194This goes in hand with the current scheme for const functions, which may also be called
166195at runtime with runtime arguments, but are checked for soundness as if they were called in
167196a 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.
169198
170199``` 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
173202}
174203```
175204
176205Using the same effect syntax from above:
177206
178207``` 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
181210}
182211```
183212
@@ -225,7 +254,7 @@ in an `impl`. This has several uses, most notably
225254In order to keep both advantages in the presence of ` impl const ` s, we need a way to declare the
226255method default body as being ` const ` . The exact syntax for doing so is left as an open question to
227256be 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.
229258
230259``` rust
231260trait Foo {
@@ -286,7 +315,7 @@ but it covers the most common cases. See also the alternatives.
286315## Effect system
287316
288317A 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
290319and this RFC is forward compatible to have its background impl be an effect system.
291320
292321## Fine grained ` const ` annotations
@@ -295,13 +324,13 @@ One could annotate methods instead of impls, allowing just marking some method i
295324as const fn. This would require some sort of "const bounds" in generic functions that
296325can be applied to specific methods. E.g. ` where <T as Add>::add: const ` or something of
297326the 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.
299328
300329## Require ` const ` bounds everywhere
301330
302331One could require ` const ` on the bounds (e.g. ` T: const Trait ` ) instead of assuming constness for all
303332bounds. 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:
305334
306335``` rust
307336fn foo <T : const Bar >() -> i32 {
@@ -318,7 +347,7 @@ annotate methods in trait impls, but we would not block calling a function on wh
318347generic parameters fulfill some sort of constness rules. Instead we'd catch this during
319348const evaluation.
320349
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
322351hazard as changing a const fn's body to suddenly call a method that it did not before can break
323352users of the function.
324353
@@ -331,7 +360,8 @@ about. Notable mentions (see also the alternatives section):
331360* const trait bounds on non-const functions allowing the use of the generic parameter in
332361 constant expressions in the body of the function or maybe even for array lenghts in the
333362 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)
335365
336366It might also be desirable to make the automatic ` Fn* ` impls on function types and pointers ` const ` .
337367This change should probably go in hand with allowing ` const fn ` pointers on const functions
@@ -483,17 +513,18 @@ themselves known:
483513
484514 is already legal in Rust today , even though the `F ` doesn 't need to be a `const ` function .
485515
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 ?
489517
490518 ```rust
491519 const fn foo (f : ? const fn () -> i32 ) -> i32 {
492520 // not allowed to call `f` here, because we can't guarantee that it points to a `const fn`
493521 }
522+ const fn foo (f : fn () -> i32 ) -> i32 {
523+ f ()
524+ }
494525 ```
495526
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 `:
497528
498529```rust
499530const fn foo (f : const fn () -> i32 ) -> i32 {
@@ -530,8 +561,42 @@ fn foo<T: const Bar>() -> i32 {
530561Which, once ` const ` items and array lengths inside of functions can make use of the generics of
531562the function, would allow the above function to actually exist.
532563
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+
533582# Unresolved questions
534583[ unresolved-questions ] : #unresolved-questions
535584
536585The syntax for specifying that a trait method's default body is ` const ` is left unspecified and uses
537586the ` #[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