From 9e9cd44ac1c17d33f162f5a2ef6b3246e7c9c049 Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Thu, 26 Sep 2024 09:24:14 -0400 Subject: [PATCH 1/2] Add identifier syntax to trait-bounds.md --- src/trait-bounds.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/trait-bounds.md b/src/trait-bounds.md index 019a2f7f0..530e978a5 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -1,5 +1,8 @@ # Trait and lifetime bounds +r[bound] + +r[bound.syntax] > **Syntax**\ > _TypeParamBounds_ :\ >    _TypeParamBound_ ( `+` _TypeParamBound_ )\* `+`? @@ -35,6 +38,7 @@ >    | [IDENTIFIER][] \ >    | `Self` +r[bound.intro] [Trait] and lifetime bounds provide a way for [generic items][generic] to restrict which types and lifetimes are used as their parameters. Bounds can be provided on any type in a [where clause]. There are also shorter forms for @@ -48,6 +52,7 @@ certain common cases: `trait A { type B: Copy; }` is equivalent to `trait A where Self::B: Copy { type B; }`. +r[bound.satisfication] Bounds on an item must be satisfied when using the item. When type checking and borrow checking a generic item, the bounds can be used to determine that a trait is implemented for a type. For example, given `Ty: Trait` @@ -87,9 +92,11 @@ fn name_figure( } ``` +r[bound.trivial] Bounds that don't use the item's parameters or [higher-ranked lifetimes] are checked when the item is defined. It is an error for such a bound to be false. +r[bound.special] [`Copy`], [`Clone`], and [`Sized`] bounds are also checked for certain generic types when using the item, even if the use does not provide a concrete type. It is an error to have `Copy` or `Clone` as a bound on a mutable reference, [trait object], or [slice]. It is an error to have `Sized` as a bound on a trait object or slice. @@ -107,16 +114,24 @@ where struct UsesA<'a, T>(A<'a, T>); ``` +r[bound.trait-object] Trait and lifetime bounds are also used to name [trait objects]. ## `?Sized` +r[bound.sized] + `?` is only used to relax the implicit [`Sized`] trait bound for [type parameters] or [associated types]. `?Sized` may not be used as a bound for other types. ## Lifetime bounds +r[bound.lifetime] + +r[bound.lifetime.intro] Lifetime bounds can be applied to types or to other lifetimes. + +r[bound.lifetime.outlive-lifetime] The bound `'a: 'b` is usually read as `'a` *outlives* `'b`. `'a: 'b` means that `'a` lasts at least as long as `'b`, so a reference `&'a ()` is valid whenever `&'b ()` is valid. @@ -127,14 +142,19 @@ fn f<'a, 'b>(x: &'a i32, mut y: &'b i32) where 'a: 'b { } ``` +r[bound.lifetime.outlive-type] `T: 'a` means that all lifetime parameters of `T` outlive `'a`. For example, if `'a` is an unconstrained lifetime parameter, then `i32: 'static` and `&'static str: 'a` are satisfied, but `Vec<&'a ()>: 'static` is not. ## Higher-ranked trait bounds +r[bound.higher-ranked] + +r[bound.higher-ranked.syntax] > _ForLifetimes_ :\ >    `for` [_GenericParams_] +r[bound.higher-ranked.intro] Trait bounds may be *higher ranked* over lifetimes. These bounds specify a bound that is true *for all* lifetimes. For example, a bound such as `for<'a> &'a T: PartialEq` would require an implementation like @@ -158,6 +178,7 @@ fn call_on_ref_zero(f: F) where for<'a> F: Fn(&'a i32) { } ``` +r[bound.higher-ranked.trait] Higher-ranked lifetimes may also be specified just before the trait: the only difference is the [scope][hrtb-scopes] of the lifetime parameter, which extends only to the end of the following trait instead of the whole bound. This function is @@ -172,15 +193,20 @@ fn call_on_ref_zero(f: F) where F: for<'a> Fn(&'a i32) { ## Implied bounds +r[bound.implied] + +r[bound.implied.intro] 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. +r[bound.implied.context] 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: @@ -203,6 +229,7 @@ fn not_implied<'a, T>() { } ``` +r[bound.implied.trait] Only lifetime bounds are implied, trait bounds still have to be explicitly added. The following example therefore causes an error: @@ -213,6 +240,7 @@ struct IsDebug(T); fn doesnt_specify_t_debug(x: IsDebug) {} ``` +r[bound.implied.def] Lifetime bounds are also inferred for type definitions and impl blocks for any type: ```rust @@ -244,6 +272,8 @@ impl<'a, T> Trait<'a, T> for &'a T {} ## Use bounds +r[bound.use] + Certain bounds lists may include a `use<..>` bound to control which generic parameters are captured by the `impl Trait` [abstract return type]. See [precise capturing] for more details. [IDENTIFIER]: identifiers.html From 14d9df2e8d5046ac2689d7521c41a71cfe18e1cc Mon Sep 17 00:00:00 2001 From: Connor Horman Date: Mon, 21 Oct 2024 12:31:42 -0400 Subject: [PATCH 2/2] Update src/trait-bounds.md Co-authored-by: Travis Cross --- src/trait-bounds.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trait-bounds.md b/src/trait-bounds.md index 530e978a5..67df9561d 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -52,7 +52,7 @@ certain common cases: `trait A { type B: Copy; }` is equivalent to `trait A where Self::B: Copy { type B; }`. -r[bound.satisfication] +r[bound.satisfaction] Bounds on an item must be satisfied when using the item. When type checking and borrow checking a generic item, the bounds can be used to determine that a trait is implemented for a type. For example, given `Ty: Trait`