Skip to content

Commit d424f1d

Browse files
committed
const generics RFC
1 parent cb97a08 commit d424f1d

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

const-generic-const-fn-bounds.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
- Feature Name: const_generic_const_fn_bounds
2+
- Start Date: 2018-10-05
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Allow `const impl`s for trait impls where all method impls are checked as const fn.
10+
11+
Make it legal to declare trait bounds on generic parameters of `const fn` and allow
12+
the body of the const fn to call methods on these generic parameters.
13+
14+
# Motivation
15+
[motivation]: #motivation
16+
17+
Currently one can declare const fns with generic parameters, but one cannot add trait bounds to these
18+
generic parameters. Thus one is not able to call methods on the generic parameters (or on objects of the
19+
generic parameter type), because they are fully unconstrained.
20+
21+
# Guide-level explanation
22+
[guide-level-explanation]: #guide-level-explanation
23+
24+
You can call call methods of generic parameters of `const fn`, because they are implicitly assumed to be
25+
`const fn`. For example, even though the `Add` trait declaration does not contain any mention of `const`,
26+
you can use it as a trait bound on your generic parameters:
27+
28+
```rust
29+
const fn triple_add<T: Add>(a: T, b: T, c: T) -> T {
30+
a + b + c
31+
}
32+
```
33+
34+
The obligation is passed to the caller of your `triple_add` function to supply a type whose `Add` impl is fully
35+
`const`. Since `Add` only has `add` as a method, in this case one only needs to ensure that the `add` method is
36+
`const fn`. Instead of adding a `const` modifier to all methods of a trait impl, the modifier is added to the entire
37+
`impl` block:
38+
39+
```rust
40+
struct MyInt(i8);
41+
const impl Add for MyInt {
42+
fn add(self, other: Self) -> Self {
43+
MyInt(self.0, other.0)
44+
}
45+
}
46+
```
47+
48+
The const requirement is propagated to all bounds of the impl or its methods,
49+
so in the following `H` is required to have a const impl of `Hasher`, so that
50+
methods on `state` are callable.
51+
52+
```rust
53+
const impl Hash for MyInt {
54+
fn hash<H>(
55+
&self,
56+
state: &mut H,
57+
)
58+
where H: Hasher
59+
{
60+
state.write(&[self.0 as u8]);
61+
}
62+
}
63+
```
64+
65+
# Reference-level explanation
66+
[reference-level-explanation]: #reference-level-explanation
67+
68+
This is the technical portion of the RFC. Explain the design in sufficient detail that:
69+
70+
- Its interaction with other features is clear.
71+
- It is reasonably clear how the feature would be implemented.
72+
- Corner cases are dissected by example.
73+
74+
The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work.
75+
76+
# Drawbacks
77+
[drawbacks]: #drawbacks
78+
79+
One cannot add trait bounds to `const fn` without them automatically
80+
requiring `const impl`s for all monomorphizations. Even if one does not
81+
call any method on the generic parameter, the methods are still required to be constant.
82+
83+
It is not a fully general design that supports every possible use case,
84+
but only covers the most common cases. See also the alternatives.
85+
86+
# Rationale and alternatives
87+
[rationale-and-alternatives]: #rationale-and-alternatives
88+
89+
## Effect system
90+
91+
A fully powered effect system can allow us to do fine grained constness propagation
92+
(or no propagation where undesirable). This is way out of scope in the near future
93+
and this RFC is forward compatible to have its background impl be an effect system.
94+
95+
## Fine grained `const` annotations
96+
97+
One could annotate methods instead of impls, allowing just marking some method impls
98+
as const fn. This would require some sort of "const bounds" in generic functions that
99+
can be applied to specific methods. E.g. `where <T as Add>::add: const` or something of
100+
the sort.
101+
102+
## Explicit `const` bounds
103+
104+
One could require `T: const Trait` bounds to differentiate between bounds on which methods
105+
can be called and bounds on which no methods can be called. This can backwards compatibly be
106+
added as an opt-out via `T: ?const Trait` if the desire for such differences is strong.
107+
108+
## Infer all the things
109+
110+
We can just throw all this complexity out the door and allow calling any method on generic
111+
parameters without an extra annotation `iff` that method satisfies `const fn`. So we'd still
112+
annotate methods in trait impls, but we would not block calling a function on whether the
113+
generic parameters fulfill some sort of constness rules. Instead we'd catch this during
114+
const evaluation.
115+
116+
This is strictly the most powerful and generic variant, but is an enormous backwards compatibility
117+
hazard as changing a const fn's body to suddenly call a method that it did not before can break
118+
users of the function.
119+
120+
# Unresolved questions
121+
[unresolved-questions]: #unresolved-questions
122+
123+
None

0 commit comments

Comments
 (0)