Skip to content

Experiment: Reborrow trait #145726

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

Merged
merged 3 commits into from
Aug 23, 2025
Merged

Conversation

aapoalas
Copy link
Contributor

@aapoalas aapoalas commented Aug 21, 2025

Tracking issue: #145612

Starting off really small here: just introduce the unstable feature and the feature gate, and one of the two traits that the Reborrow experiment deals with.

Cliff-notes explanation

The Reborrow trait is conceptually a close cousin of Copy with the exception that it disables the source (self) for the lifetime of the target / result of the reborrow action. It can be viewed as a method of fn reborrow(self: Self<'a>) -> Self<'a> with the compiler adding tracking of the resulting Self<'a> (or any value derived from it that retains the 'a lifetime) to keep the self disabled for reads and writes.

No method is planned to be surfaced to the user, however, as reborrowing cannot be seen in code (except for method calls [a.foo() reborrows a] and explicit reborrows [&*a]) and thus triggering user-code in it could be viewed as "spooky action at a distance". Furthermore, the added compiler tracking cannot be seen on the method itself, violating the Golden Rule. Note that the userland "reborrow" method is not True Reborrowing, but rather a form of a "Fancy Deref":

fn reborrow(&'short self: Self<'long>) -> Self<'short>;

The lifetime shortening is the issue here: a reborrowed Self or any value derived from it is bound to the method that called reborrow, since &'short is effectively a local variable. True Reborrowing does not shorten the lifetime of the result.

To avoid having to introduce new kinds of references, new kinds of lifetime annotations, or a blessed trait method, no method will be introduced at all. Instead, the Reborrow trait is intended to be a derived trait that effectively reborrows each field individually; Copy fields end up just copying, while fields that themselves Reborrow get disabled in the source, usually leading to the source itself being disabled (some differences may appear with structs that contain multiple reborrowable fields). The goal of the experiment is to determine how the actual implementation here will shape out, and what the "bottom case" for the recursive / deriving Reborrow is.

Reborrow has a friend trait, CoerceShared, which is equivalent to a &'a mut T -> &'a T conversion. This is needed as a different trait and different operation due to the different semantics it enforces on the source: a CoerceShared operation only disables the source for writes / exclusive access for the lifetime of the result. That trait is not yet introduced in this PR, though there is no particular reason why it could not be introduced.

@rustbot
Copy link
Collaborator

rustbot commented Aug 21, 2025

r? @petrochenkov

rustbot has assigned @petrochenkov.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Aug 21, 2025
@fmease fmease added the F-reborrow `#![feature(reborrow)]`; see #145612 label Aug 21, 2025
@tmandry
Copy link
Member

tmandry commented Aug 21, 2025

This experiment has a tracking issue (#145612) and a lang team champion, so it's good to land from a lang perspective.

@petrochenkov
Copy link
Contributor

@bors r+ rollup

@bors
Copy link
Collaborator

bors commented Aug 22, 2025

📌 Commit fd44708 has been approved by petrochenkov

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 22, 2025
jhpratt added a commit to jhpratt/rust that referenced this pull request Aug 22, 2025
… r=petrochenkov

Experiment: Reborrow trait

Tracking issue: rust-lang#145612

Starting off really small here: just introduce the unstable feature and the feature gate, and one of the two traits that the Reborrow experiment deals with.

### Cliff-notes explanation

The `Reborrow` trait is conceptually a close cousin of `Copy` with the exception that it disables the source (`self`) for the lifetime of the target / result of the reborrow action. It can be viewed as a method of `fn reborrow(self: Self<'a>) -> Self<'a>` with the compiler adding tracking of the resulting `Self<'a>` (or any value derived from it that retains the `'a` lifetime) to keep the `self` disabled for reads and writes.

No method is planned to be surfaced to the user, however, as reborrowing cannot be seen in code (except for method calls [`a.foo()` reborrows `a`] and explicit reborrows [`&*a`]) and thus triggering user-code in it could be viewed as "spooky action at a distance". Furthermore, the added compiler tracking cannot be seen on the method itself, violating the Golden Rule. Note that the userland "reborrow" method is not True Reborrowing, but rather a form of a "Fancy Deref":
```rust
fn reborrow(&'short self: Self<'long>) -> Self<'short>;
```
The lifetime shortening is the issue here: a reborrowed `Self` or any value derived from it is bound to the method that called `reborrow`, since `&'short` is effectively a local variable. True Reborrowing does not shorten the lifetime of the result.

To avoid having to introduce new kinds of references, new kinds of lifetime annotations, or a blessed trait method, no method will be introduced at all. Instead, the `Reborrow` trait is intended to be a derived trait that effectively reborrows each field individually; `Copy` fields end up just copying, while fields that themselves `Reborrow` get disabled in the source, usually leading to the source itself being disabled (some differences may appear with structs that contain multiple reborrowable fields). The goal of the experiment is to determine how the actual implementation here will shape out, and what the "bottom case" for the recursive / deriving `Reborrow` is.

`Reborrow` has a friend trait, `CoerceShared`, which is equivalent to a `&'a mut T -> &'a T` conversion. This is needed as a different trait and different operation due to the different semantics it enforces on the source: a `CoerceShared` operation only disables the source for writes / exclusive access for the lifetime of the result. That trait is not yet introduced in this PR, though there is no particular reason why it could not be introduced.
bors added a commit that referenced this pull request Aug 23, 2025
Rollup of 20 pull requests

Successful merges:

 - #132087 (Fix overly restrictive lifetime in `core::panic::Location::file` return type)
 - #137396 (Recover `param: Ty = EXPR`)
 - #142185 (Convert moves of references to copies in ReferencePropagation)
 - #144443 (Make target pointer width in target json an integer)
 - #144648 (Implementation: `#[feature(nonpoison_rwlock)]`)
 - #144897 (print raw lifetime idents with r#)
 - #145218 ([Debuginfo] improve enum value formatting in LLDB for better readability)
 - #145380 (Add codegen-llvm regression tests)
 - #145573 (Add an experimental unsafe(force_target_feature) attribute.)
 - #145597 (resolve: Remove `ScopeSet::Late`)
 - #145641 (On E0277, point at type that doesn't implement bound)
 - #145669 (rustdoc-search: GUI tests check for `//` in URL)
 - #145695 (Introduce ProjectionElem::try_map.)
 - #145710 (Fix the ABI parameter inconsistency issue in debug.rs for LoongArch64)
 - #145726 (Experiment: Reborrow trait)
 - #145731 (Make raw pointers work in type-based search)
 - #145736 (triagebot: Update style team reviewers)
 - #145738 (Uplift rustc_mir_transform::coverage::counters::union_find to rustc_data_structures.)
 - #145743 (doc: fix some typos in comment)
 - #145745 (tests: Ignore basic-stepping.rs on LoongArch)

Failed merges:

 - #145670 (port `sanitize` attribute to the new parsing infrastructure)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit that referenced this pull request Aug 23, 2025
Rollup of 28 pull requests

Successful merges:

 - #132087 (Fix overly restrictive lifetime in `core::panic::Location::file` return type)
 - #137396 (Recover `param: Ty = EXPR`)
 - #137457 (Fix host code appearing in Wasm binaries)
 - #142185 (Convert moves of references to copies in ReferencePropagation)
 - #144648 (Implementation: `#[feature(nonpoison_rwlock)]`)
 - #144897 (print raw lifetime idents with r#)
 - #145218 ([Debuginfo] improve enum value formatting in LLDB for better readability)
 - #145380 (Add codegen-llvm regression tests)
 - #145573 (Add an experimental unsafe(force_target_feature) attribute.)
 - #145597 (resolve: Remove `ScopeSet::Late`)
 - #145633 (Fix some typos in LocalKey documentation)
 - #145641 (On E0277, point at type that doesn't implement bound)
 - #145669 (rustdoc-search: GUI tests check for `//` in URL)
 - #145695 (Introduce ProjectionElem::try_map.)
 - #145710 (Fix the ABI parameter inconsistency issue in debug.rs for LoongArch64)
 - #145726 (Experiment: Reborrow trait)
 - #145731 (Make raw pointers work in type-based search)
 - #145736 (triagebot: Update style team reviewers)
 - #145738 (Uplift rustc_mir_transform::coverage::counters::union_find to rustc_data_structures.)
 - #145742 (rustdoc js: Even more typechecking improvments )
 - #145743 (doc: fix some typos in comment)
 - #145745 (tests: Ignore basic-stepping.rs on LoongArch)
 - #145747 (Refactor lint buffering to avoid requiring a giant enum)
 - #145751 (fix(lexer): Allow '-' in the frontmatter infostring continue set)
 - #145761 (Add aarch64_be-unknown-hermit target)
 - #145762 (convert strings to symbols in attr diagnostics)
 - #145763 (Ship LLVM tools for the correct target when cross-compiling)
 - #145765 (Revert suggestions for missing methods in tuples)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 566c13c into rust-lang:master Aug 23, 2025
10 checks passed
@rustbot rustbot added this to the 1.91.0 milestone Aug 23, 2025
rust-timer added a commit that referenced this pull request Aug 23, 2025
Rollup merge of #145726 - aapoalas:reborrow-lang-experiment, r=petrochenkov

Experiment: Reborrow trait

Tracking issue: #145612

Starting off really small here: just introduce the unstable feature and the feature gate, and one of the two traits that the Reborrow experiment deals with.

### Cliff-notes explanation

The `Reborrow` trait is conceptually a close cousin of `Copy` with the exception that it disables the source (`self`) for the lifetime of the target / result of the reborrow action. It can be viewed as a method of `fn reborrow(self: Self<'a>) -> Self<'a>` with the compiler adding tracking of the resulting `Self<'a>` (or any value derived from it that retains the `'a` lifetime) to keep the `self` disabled for reads and writes.

No method is planned to be surfaced to the user, however, as reborrowing cannot be seen in code (except for method calls [`a.foo()` reborrows `a`] and explicit reborrows [`&*a`]) and thus triggering user-code in it could be viewed as "spooky action at a distance". Furthermore, the added compiler tracking cannot be seen on the method itself, violating the Golden Rule. Note that the userland "reborrow" method is not True Reborrowing, but rather a form of a "Fancy Deref":
```rust
fn reborrow(&'short self: Self<'long>) -> Self<'short>;
```
The lifetime shortening is the issue here: a reborrowed `Self` or any value derived from it is bound to the method that called `reborrow`, since `&'short` is effectively a local variable. True Reborrowing does not shorten the lifetime of the result.

To avoid having to introduce new kinds of references, new kinds of lifetime annotations, or a blessed trait method, no method will be introduced at all. Instead, the `Reborrow` trait is intended to be a derived trait that effectively reborrows each field individually; `Copy` fields end up just copying, while fields that themselves `Reborrow` get disabled in the source, usually leading to the source itself being disabled (some differences may appear with structs that contain multiple reborrowable fields). The goal of the experiment is to determine how the actual implementation here will shape out, and what the "bottom case" for the recursive / deriving `Reborrow` is.

`Reborrow` has a friend trait, `CoerceShared`, which is equivalent to a `&'a mut T -> &'a T` conversion. This is needed as a different trait and different operation due to the different semantics it enforces on the source: a `CoerceShared` operation only disables the source for writes / exclusive access for the lifetime of the result. That trait is not yet introduced in this PR, though there is no particular reason why it could not be introduced.
github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Aug 24, 2025
Rollup of 28 pull requests

Successful merges:

 - rust-lang/rust#132087 (Fix overly restrictive lifetime in `core::panic::Location::file` return type)
 - rust-lang/rust#137396 (Recover `param: Ty = EXPR`)
 - rust-lang/rust#137457 (Fix host code appearing in Wasm binaries)
 - rust-lang/rust#142185 (Convert moves of references to copies in ReferencePropagation)
 - rust-lang/rust#144648 (Implementation: `#[feature(nonpoison_rwlock)]`)
 - rust-lang/rust#144897 (print raw lifetime idents with r#)
 - rust-lang/rust#145218 ([Debuginfo] improve enum value formatting in LLDB for better readability)
 - rust-lang/rust#145380 (Add codegen-llvm regression tests)
 - rust-lang/rust#145573 (Add an experimental unsafe(force_target_feature) attribute.)
 - rust-lang/rust#145597 (resolve: Remove `ScopeSet::Late`)
 - rust-lang/rust#145633 (Fix some typos in LocalKey documentation)
 - rust-lang/rust#145641 (On E0277, point at type that doesn't implement bound)
 - rust-lang/rust#145669 (rustdoc-search: GUI tests check for `//` in URL)
 - rust-lang/rust#145695 (Introduce ProjectionElem::try_map.)
 - rust-lang/rust#145710 (Fix the ABI parameter inconsistency issue in debug.rs for LoongArch64)
 - rust-lang/rust#145726 (Experiment: Reborrow trait)
 - rust-lang/rust#145731 (Make raw pointers work in type-based search)
 - rust-lang/rust#145736 (triagebot: Update style team reviewers)
 - rust-lang/rust#145738 (Uplift rustc_mir_transform::coverage::counters::union_find to rustc_data_structures.)
 - rust-lang/rust#145742 (rustdoc js: Even more typechecking improvments )
 - rust-lang/rust#145743 (doc: fix some typos in comment)
 - rust-lang/rust#145745 (tests: Ignore basic-stepping.rs on LoongArch)
 - rust-lang/rust#145747 (Refactor lint buffering to avoid requiring a giant enum)
 - rust-lang/rust#145751 (fix(lexer): Allow '-' in the frontmatter infostring continue set)
 - rust-lang/rust#145761 (Add aarch64_be-unknown-hermit target)
 - rust-lang/rust#145762 (convert strings to symbols in attr diagnostics)
 - rust-lang/rust#145763 (Ship LLVM tools for the correct target when cross-compiling)
 - rust-lang/rust#145765 (Revert suggestions for missing methods in tuples)

r? `@ghost`
`@rustbot` modify labels: rollup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-reborrow `#![feature(reborrow)]`; see #145612 S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants