Skip to content

Commit 834a259

Browse files
committed
Resolve unresolved issues and add implementation instructions
1 parent 5890176 commit 834a259

File tree

1 file changed

+58
-46
lines changed

1 file changed

+58
-46
lines changed

const-generic-const-fn-bounds.md

Lines changed: 58 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,26 @@ impl const Add for MyInt {
4646
}
4747
```
4848

49-
The const requirement is propagated to all bounds of the impl or its methods,
49+
The const requirement is required on all bounds of the impl and its methods,
5050
so in the following `H` is required to have a const impl of `Hasher`, so that
5151
methods on `state` are callable.
5252

5353
```rust
5454
impl const Hash for MyInt {
55-
fn hash<H>(
55+
const fn hash<H>(
5656
&self,
5757
state: &mut H,
5858
)
59-
where H: Hasher
59+
where H: const Hasher
6060
{
6161
state.write(&[self.0 as u8]);
6262
}
6363
}
6464
```
6565

66+
While these `const` keywords could be inferred (after all, they are required), requiring them is
67+
forward compatible to schemes in the future that allow more fine grained control.
68+
6669
## Drop
6770

6871
A notable use case of `impl const` is defining `Drop` impls. If you write
@@ -80,17 +83,67 @@ Then you are allowed to actually let a value of `SomeDropType` get dropped withi
8083
evaluation. This means `(SomeDropType(&Cell::new(42)), 42).1` is now allowed, because we can prove
8184
that everything from the creation of the value to the destruction is const evaluable.
8285

86+
## Runtime uses don't have `const` restrictions?
87+
88+
`impl const` blocks additionally generate impls that are not const if any generic
89+
parameters are not const.
90+
91+
E.g.
92+
93+
```rust
94+
impl<T: const Add> const Add for Foo<T> {
95+
fn add(self, other: Self) -> Self {
96+
Foo(self.0 + other.0)
97+
}
98+
}
99+
```
100+
101+
allows calling `Foo(String::from("foo")) + Foo(String::from("bar"))` even though that is (at the time
102+
of writing this RFC) most definitely not const, because `String` only has an `impl Add for String`
103+
and not an `impl const Add for String`.
104+
105+
This goes in hand with the current scheme for const functions, which may also be called
106+
at runtime with runtime arguments, but are checked for soundness as if they were called in
107+
a const context. E.g. the following function may be called as
108+
`add(String::from("foo"), String::from("bar"))` at runtime.
109+
110+
```rust
111+
const fn add<T: const Add>(a: T, b: T) -> T {
112+
a + b
113+
}
114+
```
115+
116+
This feature could have been added in the future in a backwards compatible manner, but without it
117+
the use of `const` impls is very restricted for the generic types of the standard library due to
118+
backwards compatibility.
119+
Changing an impl to only allow generic types which have a `const` impl for their bounds would break
120+
situations like the one described above.
121+
83122
# Reference-level explanation
84123
[reference-level-explanation]: #reference-level-explanation
85124

86125
The implementation of this RFC is (in contrast to some of its alternatives) mostly
87-
changes around the syntax of the language (adding `const` modifiers in a few places)
126+
changes around the syntax of the language (allowing `const` modifiers in a few places)
88127
and ensuring that lowering to HIR and MIR keeps track of that.
89128
The miri engine already fully supports calling methods on generic
90129
bounds, there's just no way of declaring them. Checking methods for constness is already implemented
91130
for inherent methods. The implementation will have to extend those checks to also run on methods
92131
of `impl const` items.
93132

133+
## Implementation instructions
134+
135+
1. Add an `is_const` field to the AST's `TraitRef`
136+
2. Adjust the Parser to support `const` modifiers before trait bounds
137+
3. Add an `is_const` field to the HIR's `TraitRef`
138+
4. Adjust lowering to pass through the `is_const` field from AST to HIR
139+
5. Add a a check to `librustc_typeck/check/wfcheck.rs` ensuring that all generic bounds
140+
in an `impl const` block have the `in_const` flag set and all methods' `constness` field is
141+
`Const`.
142+
6. Feature gate instead of ban `Predicate::Trait` other than `Sized` in
143+
`librustc_mir/transform/qualify_min_const_fn.rs`
144+
7. Remove the call in https://github.com/rust-lang/rust/blob/f8caa321c7c7214a6c5415e4b3694e65b4ff73a7/src/librustc_passes/ast_validation.rs#L306
145+
8. Adjust the reference and the book to reflect these changes.
146+
94147
# Drawbacks
95148
[drawbacks]: #drawbacks
96149

@@ -211,45 +264,4 @@ and `const` modifiers on `impl` blocks.
211264
# Unresolved questions
212265
[unresolved-questions]: #unresolved-questions
213266

214-
## Runtime uses don't have `const` restrictions?
215-
216-
Should `impl const` blocks additionally generate impls that are not const if any generic
217-
parameters are not const?
218-
219-
E.g.
220-
221-
```rust
222-
impl<T: Add> const Add for Foo<T> {
223-
fn add(self, other: Self) -> Self {
224-
Foo(self.0 + other.0)
225-
}
226-
}
227-
```
228-
229-
would allow calling `Foo(String::from("foo")) + Foo(String::from("bar"))` even though that is (at the time
230-
of writing this RFC) most definitely not const, because `String` only has an `impl Add for String`
231-
and not an `impl const Add for String`.
232-
233-
This would go in hand with the current scheme for const functions, which may also be called
234-
at runtime with runtime arguments, but are checked for soundness as if they were called in
235-
a const context.
236-
237-
## Require `const` bounds on everything inside an `impl const` block?
238-
239-
Instead of inferring `const`ness on all bounds and functions inside a `impl const` block,
240-
we force the user to supply these bounds. This is more consistent with not inferring `const`
241-
on `const` function argument types and generic bounds. The `Hash` example from above would
242-
then look like
243-
244-
```rust
245-
impl const Hash for MyInt {
246-
const fn hash<H>(
247-
&self,
248-
state: &mut H,
249-
)
250-
where H: const Hasher
251-
{
252-
state.write(&[self.0 as u8]);
253-
}
254-
}
255-
```
267+
Everything has been addressed in the reviews

0 commit comments

Comments
 (0)