Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add capturing and precise capturing rules #1577

Merged
merged 1 commit into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/names/scopes.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ type FnExample = for<'a> fn(x: Example<'a>) -> Example<'a>;
#
// The `impl Trait2` here is not allowed to refer to 'b but it is allowed to
// refer to 'a.
fn foo<'a>() -> impl for<'b> Trait1<Item = impl Trait2<'a>> {
fn foo<'a>() -> impl for<'b> Trait1<Item = impl Trait2<'a> + use<'a>> {
// ...
# Example
}
Expand Down
23 changes: 22 additions & 1 deletion src/trait-bounds.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
> &nbsp;&nbsp; _TypeParamBound_ ( `+` _TypeParamBound_ )<sup>\*</sup> `+`<sup>?</sup>
>
> _TypeParamBound_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; _Lifetime_ | _TraitBound_
> &nbsp;&nbsp; &nbsp;&nbsp; _Lifetime_ | _TraitBound_ | _UseBound_
>
> _TraitBound_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; `?`<sup>?</sup>
Expand All @@ -19,6 +19,21 @@
> _Lifetime_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; [LIFETIME_OR_LABEL]\
> &nbsp;&nbsp; | `'static`
>
> _UseBound_ :\
> &nbsp;&nbsp; `use` _UseBoundGenericArgs_
>
> _UseBoundGenericArgs_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; `<` `>` \
> &nbsp;&nbsp; | `<` \
> &nbsp;&nbsp; &nbsp;&nbsp; ( _UseBoundGenericArg_ `,`)<sup>\*</sup> \
> &nbsp;&nbsp; &nbsp;&nbsp; _UseBoundGenericArg_ `,`<sup>?</sup> \
> &nbsp;&nbsp; &nbsp;&nbsp; `>`
>
> _UseBoundGenericArg_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; _Lifetime_ \
> &nbsp;&nbsp; | [IDENTIFIER][] \
> &nbsp;&nbsp; | `Self`
[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
Expand Down Expand Up @@ -227,20 +242,26 @@ trait Trait<'a, T: 'a> {}
impl<'a, T> Trait<'a, T> for &'a T {}
```

## Use bounds

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
[LIFETIME_OR_LABEL]: tokens.md#lifetimes-and-loop-labels
[_GenericParams_]: items/generics.md
[_TypePath_]: paths.md#paths-in-types
[`Clone`]: special-types-and-traits.md#clone
[`Copy`]: special-types-and-traits.md#copy
[`Sized`]: special-types-and-traits.md#sized

[abstract return type]: types/impl-trait.md#abstract-return-types
[arrays]: types/array.md
[associated types]: items/associated-items.md#associated-types
[hrtb-scopes]: names/scopes.md#higher-ranked-trait-bound-scopes
[supertraits]: items/traits.md#supertraits
[generic]: items/generics.md
[higher-ranked lifetimes]: #higher-ranked-trait-bounds
[precise capturing]: types/impl-trait.md#precise-capturing
[slice]: types/slice.md
[Trait]: items/traits.md#trait-bounds
[trait object]: types/trait-object.md
Expand Down
33 changes: 30 additions & 3 deletions src/types/impl-trait.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,33 @@ Functions in traits may also use `impl Trait` as a syntax for an anonymous assoc

Every `impl Trait` in the return type of an associated function in a trait is desugared to an anonymous associated type. The return type that appears in the implementation's function signature is used to determine the value of the associated type.

### Differences between generics and `impl Trait` in return position
## Capturing

Behind each return-position `impl Trait` abstract type is some hidden concrete type. For this concrete type to use a generic parameter, that generic parameter must be *captured* by the abstract type.

## Automatic capturing

Return-position `impl Trait` abstract types automatically capture certain of the in-scope generic parameters. Everywhere, these automatically capture all in-scope type and const generic parameters.

On items of trait impls and trait definitions, these types additionally automatically capture all in-scope generic lifetime parameters, including higher-ranked ones. On free functions and on associated functions and methods of inherent impls, only the generic lifetime parameters that appear in the bounds of abstract return type are captured.

## Precise capturing

The set of generic parameters captured by a return-position `impl Trait` abstract type may be explicitly controlled with a [`use<..>` bound]. If present, only the generic parameters listed in the `use<..>` bound will be captured. E.g.:

```rust
fn capture<'a, 'b, T>(x: &'a (), y: T) -> impl Sized + use<'a, T> {
// ~~~~~~~~~~~~~~~~~~~~~~~
// Captures `'a` and `T` only.
(x, y)
}
```

Currently, only one `use<..>` bound may be present in a bounds list, such bounds are not allowed in the signature of items of a trait definition, all in-scope type and const generic parameters must be included, and all lifetime parameters that appear in other bounds of the abstract type must be included. Within the `use<..>` bound, any lifetime parameters present must appear before all type and const generic parameters, and the elided lifetime (`'_`) may be present if it is otherwise allowed to appear within the `impl Trait` return type.

Because all in-scope type parameters must be included by name, a `use<..>` bound may not be used in the signature of items that use argument-position `impl Trait`, as those items have anonymous type parameters in scope.

traviscross marked this conversation as resolved.
Show resolved Hide resolved
## Differences between generics and `impl Trait` in return position

In argument position, `impl Trait` is very similar in semantics to a generic type parameter.
However, there are significant differences between the two in return position.
Expand Down Expand Up @@ -127,9 +153,10 @@ Instead, the function chooses the return type, but only promises that it will im
`impl Trait` can only appear as a parameter or return type of a non-`extern` function.
It cannot be the type of a `let` binding, field type, or appear inside a type alias.

[closures]: closure.md
[_GenericArgs_]: ../paths.md#paths-in-expressions
[_GenericParams_]: ../items/generics.md
[_TraitBound_]: ../trait-bounds.md
[trait object]: trait-object.md
[_TypeParamBounds_]: ../trait-bounds.md
[`use<..>` bound]: ../trait-bounds.md#use-bounds
[closures]: closure.md
[trait object]: trait-object.md