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

SemVer: Add section on RPIT capturing #14849

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
42 changes: 42 additions & 0 deletions src/doc/src/reference/semver.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ considered incompatible.
* [Minor: generalizing a type to use generics (with identical types)](#generic-generalize-identical)
* [Major: generalizing a type to use generics (with possibly different types)](#generic-generalize-different)
* [Minor: changing a generic type to a more generic type](#generic-more-generic)
* [Major: capturing more generic parameters in RPIT](#generic-rpit-capture)
* Functions
* [Major: adding/removing function parameters](#fn-change-arity)
* [Possibly-breaking: introducing a new function type parameter](#fn-generic-new)
Expand Down Expand Up @@ -1616,6 +1617,47 @@ fn main() {
}
```

### Major: capturing more generic parameters in RPIT {#generic-rpit-capture}

It is a breaking change to capture additional generic parameters in an [RPIT] (return-position impl trait).

```rust,ignore
// MAJOR CHANGE

///////////////////////////////////////////////////////////
// Before
pub fn f<'a, 'b>(x: &'a str, y: &'b str) -> impl Iterator<Item = char> + use<'a> {
x.chars()
}

///////////////////////////////////////////////////////////
// After
pub fn f<'a, 'b>(x: &'a str, y: &'b str) -> impl Iterator<Item = char> + use<'a, 'b> {
x.chars().chain(y.chars())
}

///////////////////////////////////////////////////////////
// Example usage that will break.
fn main() {
let a = String::new();
let b = String::new();
let iter = updated_crate::f(&a, &b);
drop(b); // Error: cannot move out of `b` because it is borrowed
}
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A thought: would it be worth adding an example, or even just mentioning in a sentence or two that use<> syntax can also be used to capture type parameters, not just lifetimes? That wasn't immediately obvious to me when I first heard about this new language feature.


Adding generic parameters to an RPIT places additional constraints on how the resulting type may be used.

Note that there are implicit captures when the `use<>` syntax is not specified. In Rust 2021 and earlier editions, the lifetime parameters are only captured if they appear syntactically within a bound in the RPIT type signature. Starting in Rust 2024, all lifetime parameters are unconditionally captured. This means that starting in Rust 2024, the default is maximally compatible, requiring you to be explicit when you want to capture less, which is a SemVer commitment.

See the [edition guide][rpit-capture-guide] and the [reference][rpit-reference] for more information on RPIT capturing.

It is a minor change to capture fewer generic parameters in an RPIT.
Copy link
Member

@obi1kenobi obi1kenobi Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this might not be true for functions in non-sealed traits. If the trait's function definition changes the RPIT captures, I expect implementations of the trait have to be updated to match.


[RPIT]: ../../reference/types/impl-trait.md#abstract-return-types
[rpit-capture-guide]: ../../edition-guide/rust-2024/rpit-lifetime-capture.html
[rpit-reference]: ../../reference/types/impl-trait.md#capturing

### Major: adding/removing function parameters {#fn-change-arity}

Changing the arity of a function is a breaking change.
Expand Down