Skip to content

Commit

Permalink
Merge pull request #1261 from lcnr/implied-bounds
Browse files Browse the repository at this point in the history
add section about implied bounds
  • Loading branch information
ehuss authored Aug 10, 2023
2 parents 2a8068e + f24f128 commit f7e6f04
Showing 1 changed file with 73 additions and 0 deletions.
73 changes: 73 additions & 0 deletions src/trait-bounds.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,79 @@ fn call_on_ref_zero<F>(f: F) where F: for<'a> Fn(&'a i32) {
}
```

## Implied bounds

Lifetime bounds required for types to be well-formed are sometimes inferred.

```rust
fn requires_t_outlives_a<'a, T>(x: &'a T) {}
```
The type parameter `T` is required to outlive `'a` for the type `&'a T` to be well-formed.
This is inferred because the function signature contains the type `&'a T` which is
only valid if `T: 'a` holds.

Implied bounds are added for all parameters and outputs of functions. Inside of `requires_t_outlives_a`
you can assume `T: 'a` to hold even if you don't explicitly specify this:

```rust
fn requires_t_outlives_a_not_implied<'a, T: 'a>() {}

fn requires_t_outlives_a<'a, T>(x: &'a T) {
// This compiles, because `T: 'a` is implied by
// the reference type `&'a T`.
requires_t_outlives_a_not_implied::<'a, T>();
}
```

```rust,compile_fail,E0309
# fn requires_t_outlives_a_not_implied<'a, T: 'a>() {}
fn not_implied<'a, T>() {
// This errors, because `T: 'a` is not implied by
// the function signature.
requires_t_outlives_a_not_implied::<'a, T>();
}
```

Only lifetime bounds are implied, trait bounds still have to be explicitly added.
The following example therefore causes an error:

```rust,compile_fail,E0277
use std::fmt::Debug;
struct IsDebug<T: Debug>(T);
// error[E0277]: `T` doesn't implement `Debug`
fn doesnt_specify_t_debug<T>(x: IsDebug<T>) {}
```

Lifetime bounds are also inferred for type definitions and impl blocks for any type:

```rust
struct Struct<'a, T> {
// This requires `T: 'a` to be well-formed
// which is inferred by the compiler.
field: &'a T,
}

enum Enum<'a, T> {
// This requires `T: 'a` to be well-formed,
// which is inferred by the compiler.
//
// Note that `T: 'a` is required even when only
// using `Enum::OtherVariant`.
SomeVariant(&'a T),
OtherVariant,
}

trait Trait<'a, T: 'a> {}

// This would error because `T: 'a` is not implied by any type
// in the impl header.
// impl<'a, T> Trait<'a, T> for () {}

// This compiles as `T: 'a` is implied by the self type `&'a T`.
impl<'a, T> Trait<'a, T> for &'a T {}
```


[LIFETIME_OR_LABEL]: tokens.md#lifetimes-and-loop-labels
[_GenericParams_]: items/generics.md
[_TypePath_]: paths.md#paths-in-types
Expand Down

0 comments on commit f7e6f04

Please sign in to comment.