Merge pull request #1261 from lcnr/implied-bounds

add section about implied bounds
This commit is contained in:
Eric Huss 2023-08-10 20:48:56 +00:00 committed by GitHub
commit f7e6f0445b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 73 additions and 0 deletions

View File

@ -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