Skip to content

Commit f7e6f04

Browse files
authored
Merge pull request #1261 from lcnr/implied-bounds
add section about implied bounds
2 parents 2a8068e + f24f128 commit f7e6f04

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

src/trait-bounds.md

+73
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,79 @@ fn call_on_ref_zero<F>(f: F) where F: for<'a> Fn(&'a i32) {
156156
}
157157
```
158158

159+
## Implied bounds
160+
161+
Lifetime bounds required for types to be well-formed are sometimes inferred.
162+
163+
```rust
164+
fn requires_t_outlives_a<'a, T>(x: &'a T) {}
165+
```
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.
169+
170+
Implied bounds are added for all parameters and outputs of functions. Inside of `requires_t_outlives_a`
171+
you can assume `T: 'a` to hold even if you don't explicitly specify this:
172+
173+
```rust
174+
fn requires_t_outlives_a_not_implied<'a, T: 'a>() {}
175+
176+
fn requires_t_outlives_a<'a, T>(x: &'a T) {
177+
// This compiles, because `T: 'a` is implied by
178+
// the reference type `&'a T`.
179+
requires_t_outlives_a_not_implied::<'a, T>();
180+
}
181+
```
182+
183+
```rust,compile_fail,E0309
184+
# fn requires_t_outlives_a_not_implied<'a, T: 'a>() {}
185+
fn not_implied<'a, T>() {
186+
// This errors, because `T: 'a` is not implied by
187+
// the function signature.
188+
requires_t_outlives_a_not_implied::<'a, T>();
189+
}
190+
```
191+
192+
Only lifetime bounds are implied, trait bounds still have to be explicitly added.
193+
The following example therefore causes an error:
194+
195+
```rust,compile_fail,E0277
196+
use std::fmt::Debug;
197+
struct IsDebug<T: Debug>(T);
198+
// error[E0277]: `T` doesn't implement `Debug`
199+
fn doesnt_specify_t_debug<T>(x: IsDebug<T>) {}
200+
```
201+
202+
Lifetime bounds are also inferred for type definitions and impl blocks for any type:
203+
204+
```rust
205+
struct Struct<'a, T> {
206+
// This requires `T: 'a` to be well-formed
207+
// which is inferred by the compiler.
208+
field: &'a T,
209+
}
210+
211+
enum Enum<'a, T> {
212+
// This requires `T: 'a` to be well-formed,
213+
// which is inferred by the compiler.
214+
//
215+
// Note that `T: 'a` is required even when only
216+
// using `Enum::OtherVariant`.
217+
SomeVariant(&'a T),
218+
OtherVariant,
219+
}
220+
221+
trait Trait<'a, T: 'a> {}
222+
223+
// This would error because `T: 'a` is not implied by any type
224+
// in the impl header.
225+
// impl<'a, T> Trait<'a, T> for () {}
226+
227+
// This compiles as `T: 'a` is implied by the self type `&'a T`.
228+
impl<'a, T> Trait<'a, T> for &'a T {}
229+
```
230+
231+
159232
[LIFETIME_OR_LABEL]: tokens.md#lifetimes-and-loop-labels
160233
[_GenericParams_]: items/generics.md
161234
[_TypePath_]: paths.md#paths-in-types

0 commit comments

Comments
 (0)