Skip to content

Commit cb0c2a4

Browse files
aapoalastmandrylqdtomassedovic
authored
Proposal: Autoreborrow traits (#339)
* Proposal: Autoreborrow traits * md validity * metadata: Teams * revert * remove "closes" Co-authored-by: Tyler Mandry <tmandry@gmail.com> * Update src/2025h2/autoreborrow-traits.md Co-authored-by: Rémy Rakic <remy.rakic+github@gmail.com> * Update src/2025h2/autoreborrow-traits.md Co-authored-by: Rémy Rakic <remy.rakic+github@gmail.com> * Update src/2025h2/autoreborrow-traits.md Co-authored-by: Rémy Rakic <remy.rakic+github@gmail.com> * Fix CI by removing duplicated Teams table with incorrect value --------- Co-authored-by: Tyler Mandry <tmandry@gmail.com> Co-authored-by: Rémy Rakic <remy.rakic+github@gmail.com> Co-authored-by: Tomas Sedovic <tomas@sedovic.cz>
1 parent 4993e06 commit cb0c2a4

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed

src/2025h2/autoreborrow-traits.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Nightly support for Autoreborrow traits
2+
3+
| Metadata | |
4+
|:-----------------|----------------------------------------------------------------------------------|
5+
| Point of contact | @aapoalas |
6+
| Teams | <!-- TEAMS WITH ASKS --> |
7+
| Task owners | <!-- TASK OWNERS --> |
8+
| Status | Proposed |
9+
| Tracking issue | |
10+
| Zulip channel | N/A (an existing stream can be re-used or new streams can be created on request) |
11+
12+
## Summary
13+
14+
Bring up a language RFC for autoreborrow traits and land nightly support for the traits.
15+
16+
## Motivation
17+
18+
Reborrowing is an important feature of the Rust ecosystem, underpinning much of the borrow checker's work and
19+
enabling ergonomic usage of references. The built-in, automatic handling of reborrows as a language feature
20+
is, arguably, one of the many keys to Rust's success. Autoreborrowing is not available for user-space types
21+
to take advantage of, which hinders their ergonomics and usage.
22+
23+
Autoreborrowing is a necessary feature for both niche use-cases around lifetime trickery, and for flagship
24+
goals like Pin-ergonomics and the Rust for Linux project. As both of these are proceeding, a parallel track
25+
to pre-empt reborrowing becoming a sticking point seems wise. Luckily, reborrowing is arguably a solved
26+
problem that mostly needs a formal definition and a implementation choice to enter the language formally.
27+
28+
### The status quo
29+
30+
Today, when an `Option<&mut T>` or `Pin<&mut T>` is passed as a parameter, it becomes unavailable to the
31+
caller because it gets moved out of. This makes sense insofar as `Option<T>` only being `Copy` if `T: Copy`,
32+
which `&mut T` is not. But it makes no sense from the point of view of `&mut T` specifically: passing an
33+
exclusive reference does not move the reference but instead reborrows it, allowing the `&mut T` to be reused
34+
after the call finishes. Since an `Option<&mut T>` is simply a maybe-null `&mut T` it would make sense that
35+
it would have the same semantics.
36+
37+
The lack of autoreborrowing is why this is not the case. This can be overcome by using the `.as_deref_mut()`
38+
method but it suffers from lifetime issues when the callee returns a value derived from the `&mut T`: that
39+
returned value cannot be returned again from the caller as its lifetime is bound to the `.as_deref_mut()`
40+
call. For `Pin<&mut T>` this problem has been side-stepped by adding `Pin`-specific nightly support of
41+
reborrowing pinned exclusive references.
42+
43+
But the same issue pops up again for any user-defined exclusive reference types, such as `Mut<'_, T>`. The
44+
user can define this type as having exclusive semantics by not making the type `Copy`, but they cannot opt
45+
into automatic reborrowing. The best they can hope is to implement a custom `.reborrow_mut()` method similar
46+
to the `Option::as_deref_mut` from above. Here again they run into the issue that the lifetime of a
47+
`Mut<'_, T>` always gets constrained to the `.reborrow_mut()` call, making it impossible to return
48+
values derived from a `Mut<'_, T>` from the function that called `.reborrow_mut()`.
49+
50+
An improvement is needed.
51+
52+
### The next 6 months
53+
54+
- Bring up an RFC for autoreborrowing: a
55+
[draft](https://github.com/aapoalas/rfcs/blob/autoreborrow-traits/text/0000-autoreborrow-traits.md) exists.
56+
- Choose the internal logic of recursive reborrowing: based on core marker types, or on interaction with
57+
`Copy`?
58+
- Implement nightly support for non-recursive reborrowing.
59+
- Gather feedback from users, especially `reborrow` crate users.
60+
- Implement nightly support for recursive reborrowing.
61+
62+
### The "shiny future" we are working towards
63+
64+
`Pin` ergonomics group should be able to get rid of special-casing of `Pin` reborrowing in rustc.
65+
66+
Rust for Linux project should be enabled to experiment with custom reborrowable reference types in earnest.
67+
68+
Users of `reborrow` crate and similar should be enabled to move to core solution.
69+
70+
## Design axioms
71+
72+
- Accept the definition of reborrowing as "a memory copy with added lifetime analysis".
73+
- This disallows running user code on reborrow.
74+
- "Reborrow-as-shared" likely needs to run user code; this'd preferably be ignored where possible.
75+
- Must achieve true reborrowing, not a fascimile.
76+
- Current userland reborrowing uses `T::reborrow_mut` functions that achieve the most important part of
77+
reborrowing, temporarily disabled `T` upon reborrow.
78+
- Userland cannot achieve true reborrowing: true reborrowing does not constrain the lifetime of `T`,
79+
whereas userland fascimile does.
80+
- Difference is in whether values derived from a reborrow can be returned past the point of the reborrow.
81+
- Performance of the solution must be trivial: reborrow is checked for at every coercion site. This cannot be
82+
slow.
83+
- Make sure autoreborrowing doesn't become a vehicle for implicit type coercion. Allowing autoreborrowing
84+
from `T` to multiple values could be abused to define a `CustomInt(int128)` that coerces to all integer
85+
types.
86+
- Autoreborrow traits should use an associated type instead of a type parameter.
87+
- Autoreborrowing at coercion sites should not dovetail into eg. an `Into::into` call.
88+
89+
## Ownership and team asks
90+
91+
| Task | Owner(s) or team(s) | Notes |
92+
|------------------------------|---------------------|-------|
93+
| Discussion and moral support | ![Team][] [lang] | Normal RFC process |
94+
| Standard reviews | ![Team][] [compiler]| Trait-impl querying in rustc to replace `Pin<&mut T>` special case |
95+
| Do the work | @aapoalas | |
96+
97+
### Design autoreborrow internals
98+
99+
The basic idea of autoreborrowing is simple enough: when a reborrowable type is encountered at a coercion
100+
site, attempt a reborrow operation.
101+
102+
Complications arise when reborrowing becomes recursive: if a `struct X { a: A, b: B }` contains two
103+
reborrowable types `A` and `B`, then we'd want the reborrow of `X` to be performed "piecewise". As an
104+
example, the following type should, upon reborrow, only invalidate any values that depend on the `'a` lifetime while any values dependent on the `'b` lifetime should still be usable as normal.
105+
106+
```rust
107+
struct X<'a, 'b> {
108+
a: &'a mut A,
109+
b: &'b B,
110+
}
111+
```
112+
113+
To enable this, reborrowing needs to be defined as a recursive operation but what the "bottom-case" is, that
114+
is the question. One option would be to use `!Copy + Reborrow` fields, another would use core marker types
115+
like `PhantomExclusive<'a>` and `PhantomShared<'b>` to discern the difference.
116+
117+
118+
| Task | Owner(s) or team(s) | Notes |
119+
|----------------------|------------------------------------|---------------------------------------------------------------------|
120+
| Lang-team experiment | ![Team][] [lang] | allows coding pre-RFC; only for trusted contributors |
121+
| Author RFC | *Goal point of contact, typically* | |
122+
| Lang-team champion | ![Team][] [lang] | Username here |
123+
| RFC decision | ![Team][] [lang] | |
124+
| RFC secondary review | ![Team][] [types] | request bandwidth from a second team, most features don't need this |
125+
126+
### Implement non-recursive autoreborrowing
127+
128+
A basic autoreborrowing feature should not be too complicated: the `Pin<&mut T>` special-case in the
129+
compiler already exists and could probably be reimagined to rely on a `Reborrow` trait.
130+
131+
| Task | Owner(s) or team(s) | Notes |
132+
|-----------------------------------|------------------------------------|-------|
133+
| Implementation | *Goal point of contact, typically* | |
134+
| Standard reviews | ![Team][] [compiler] | |
135+
| Lang-team champion | ![Team][] [lang] | |
136+
| Design meeting | ![Team][] [lang] | |
137+
| Author call for testing blog post | *Goal point of contact, typically* | |
138+
139+
## Frequently asked questions

0 commit comments

Comments
 (0)