Skip to content

Commit 903009a

Browse files
lcnrehuss
authored andcommitted
review
1 parent f01e75f commit 903009a

File tree

1 file changed

+41
-8
lines changed

1 file changed

+41
-8
lines changed

src/trait-bounds.md

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -158,41 +158,74 @@ fn call_on_ref_zero<F>(f: F) where F: for<'a> Fn(&'a i32) {
158158

159159
## Implied bounds
160160

161-
Rust sometimes infers some bounds the user would have otherwise been required to write.
161+
Lifetime bounds required for types to be well-formed are sometimes inferred by the compiler.
162162

163163
```rust
164164
fn requires_t_outlives_a<'a, T>(x: &'a T) {}
165165
```
166-
While this function requires `T` to outlive `'a`, this is inferred because the function signature
167-
contains the type `&'a T` which is only valid if `T: 'a` holds.
166+
The type parameter `T` is required to outlive `'a` for the type `&'a T` to be well-formed.
167+
This is inferred because the function signature contains the type `&'a T` which is
168+
only valid if `T: 'a` holds.
168169

169170
Rust adds implied bounds for all inputs and outputs of functions. Inside of `requires_t_outlives_a`
170171
you can assume `T: 'a` to hold even if you don't explicitly specify this:
171-
```rust,compile_fail
172+
```rust
173+
fn requires_t_outlives_a_not_implied<'a, T: 'a>() {}
174+
172175
fn requires_t_outlives_a<'a, T>(x: &'a T) {
173176
// This compiles, because `T: 'a` is implied by
174177
// the reference type `&'a T`.
175178
requires_t_outlives_a_not_implied::<'a, T>();
176179
}
180+
```
177181

182+
```rust,compile_fail
183+
# fn requires_t_outlives_a_not_implied<'a, T: 'a>() {}
178184
fn not_implied<'a, T>() {
179185
// This errors, because `T: 'a` is not implied by
180186
// the function signature.
181187
requires_t_outlives_a_not_implied::<'a, T>();
182188
}
183-
184-
fn requires_t_outlives_a_not_implied<'a, T: 'a>() {}
185189
```
186190

187-
Only lifetime bounds are implied, trait bounds still have to be explicitly added.
188-
This behavior may change in the future however. The following example still causes an error:
191+
Only lifetime bounds are implied, trait bounds still have to be explicitly added. The following example therefore causes an error:
189192
```rust,compile_fail
190193
use std::fmt::Debug;
191194
struct IsDebug<T: Debug>(T);
192195
// error[E0277]: `T` doesn't implement `Debug`
193196
fn doesnt_specify_t_debug<T>(x: IsDebug<T>) {}
194197
```
195198

199+
Lifetime bounds are also inferred in type definitions and impl blocks.
200+
201+
```rust
202+
struct Struct<'a, T> {
203+
// This requires `T: 'a` to be well-formed
204+
// which is inferred by the compiler.
205+
field: &'a T,
206+
}
207+
208+
enum Enum<'a, T> {
209+
// This requires `T: 'a` to be well-formed,
210+
// which is inferred by the compiler.
211+
//
212+
// Note that `T: 'a` is required even when only
213+
// using `Enum::OtherVariant`.
214+
SomeVariant(&'a T),
215+
OtherVariant,
216+
}
217+
218+
trait Trait<'a, T: 'a> {}
219+
220+
// This would error because `T: 'a` is not implied by any type
221+
// in the impl header.
222+
// impl<'a, T> Trait<'a, T> for () {}
223+
224+
// This compiles as `T: 'a` is implied by the self type `&'a ()`.
225+
impl<'a, T> Trait<'a, T> for &'a T {}
226+
```
227+
228+
196229
[LIFETIME_OR_LABEL]: tokens.md#lifetimes-and-loop-labels
197230
[_GenericParams_]: items/generics.md
198231
[_TypePath_]: paths.md#paths-in-types

0 commit comments

Comments
 (0)