# Reborrow trait

**URL:** <https://internals.rust-lang.org/t/reborrow-trait/20774>\
**Category:** language design\
**Created:** [May 6, 2024, 1:54am UTC](https://internals.rust-lang.org/t/reborrow-trait/20774 "2024-05-06T01:54:17Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [May 6, 2024, 1:54am UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/1 "2024-05-06T01:54:17Z")

</div>

# The problem

This works:

```rust
fn foo<T>(param: &mut T) {}

fn foo_twice<T>(param: &mut T) {
    foo(param);
    foo(param);
}

```

This doesn't:

```rust
fn foo<T>(param: Pin<&mut T>) {}

fn foo_twice<T>(param: Pin<&mut T>) {
    foo(param);
    foo(param);
}

```

That's a problem.

# Why this should be a priority

The language and library teams want to stabilize `AsyncIterator` within the next few months. Ideally, convenience methods like [`next()`](https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html#method.next) should soon follow. For maximum flexibility, these methods should take `Pin<&mut Self>`. But if `Pin<&mut Self>` is painful to use, that defeats the whole purpose of convenience methods!

# Prior work

[RFC 2364](https://github.com/dhardy/rfcs/blob/reborrow/text/0000-formalise-reborrows.md) (postponed) proposed to formalize a `Reborrow` trait. But the definition of the trait had a problem:

> We introduce the following trait, as member of `std::marker`:
> 
> ```rust
> trait Reborrow { fn reborrow(&self) -> ???; }
> 
> ```
> 
> Unfortunately the return type of `fn reborrow` isn't representable in general; the return type must be `Self` but with different lifetime(s) (and note that there will be multiple lifetimes if the type has multiple fields with lifetimes). It is not possible to use an associated type `type Result: ???` because the return type includes a lifetime (or multiple) bound by the caller.

Let's try again.

# `Reborrow` take 2

**EDIT: see new design [here](https://internals.rust-lang.org/t/reborrow-trait/20774/6)**

## Signature

Here's the definition of `Reborrow`:

```rust
#[lang = "reborrow"]
#[marker]
pub trait Reborrow {}

impl<T: Copy + ?Sized> Reborrow for T { }

impl<'a, T: ?Sized> Reborrow for &'a mut T { }

```

And here's the new definition of `Copy`:

```rust
#[lang = "copy"]
#[marker]
pub trait Copy: Clone + Reborrow { }

```

Just as with `Copy`:

- A type can implement `Reborrow` iff the types of all its fields implement it.
- There is a built-in `derive` macro for implementing `Reborrow`.
- `Reborrow` types cannot also be `Drop`.

## Semantics

For any two types `Super` and `Sub`, such that `Super` is a supertype of `Sub`:

```rust
fn foo(arg: Sub) {
    let local: Super = arg;
    // HERE
}

```

At the point marked `HERE`:

- If `Sub` implements `Copy`, `arg` remains fully accessible.
- If `Sub` implements neither `Copy` nor `Reborrow`, `arg` is permanently inaccessible.
- **New:** if `Sub` implements `Reborrow` but not `Copy`, `arg` is inaccessible only until `Super`'s lifetime ends.

That is all.

## Wait, how do you reborrow `Wrapper<&mut T>` as `Wrapper<&T>` with this proposal?

You don't ☹ . At least, not until `&mut T` becomes a subtype of `&T`. But that's a problem for another day…

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [May 6, 2024, 3:18am UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/2 "2024-05-06T03:18:28Z")

</div>

> [@Jules-Bertholet](#):
>
> `impl<T: Copy + ?Sized> Reborrow for T { }`

Nit: `Copy` has `Sized` as a supertrait (via `Clone`).

* * *

What else in `std` or the base language implements `Reborrow`? `PhantomData<_>` I guess. How about `UnsafeCell`?

* * *

> [@Jules-Bertholet](#):
>
> if `Super` implements `Reborrow` but not `Copy`, `arg` is inaccessible only until `Super`'s lifetime ends.

Can you be more precise? For example, does this:

```rust
#[derive(Reborrow)]
struct S<'a> {
    r: &'a str,
    m: &'a mut str,
}

fn ex(s: S<'_>) {
    let s2 = s.reborrow();
}

```

Act like this?

```rust
impl<'a> S<'a> {
    fn reborrow(&mut self) -> S<'_> {
        S { r: self.r, m: self.m }
    }
}

fn ex(mut s: S<'_>) {
    let s2 = s.reborrow();
}

```

(If so, `&mut _` reborrowing is something different.)

Or does it act like this?

```rust
    let s2 = S { r: s.r, s: s.m };

```

(If so, `*s.r` is not reborrowed, but `*s.m` is.)

---

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [May 6, 2024, 3:33am UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/3 "2024-05-06T03:33:55Z")

</div>

Probably like the latter? Since it's strictly more useful. So this would work:

```rust
#[derive(Reborrow, Debug)]
struct S<'a> {
    r: &'a str,
    m: &'a mut str,
}

fn ex(s: S<'_>) {
    let s2 = s;
    dbg!(s.r);
    drop(s2);
}

```

However, this wouldn't:

```rust
fn ex2(s: S<'_>) {
    let s2 = s;
    dbg!(s);
    drop(s2);
}

```

Nor would this:

```rust
// Could be `Copy`, but isn't
#[derive(Reborrow, Debug)]
struct S2<'a> {
    r: &'a str,
    m: &'a str,
}

fn ex3(s: S2<'_>) {
    let s2 = s;
    dbg!(s);
    drop(s2);
}

```

---

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [May 6, 2024, 3:37am UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/4 "2024-05-06T03:37:10Z")

</div>

> [@quinedot](#):
>
> What else in `std` or the base language implements `Reborrow`? `PhantomData<_>` I guess. How about `UnsafeCell`?

`PhantomData<_>` is already `Copy`, and therefore needs no separate `Reborrow` implementation.

`UnsafeCell<T>` is invariant in `T`, so an implementation of `Reborrow` would be pointless (as there is no supertype to reborrow it as).

Basically any generic container that implements `Copy` will want to implement `Reborrow` as well. (`Poll`, `Option`, `Result`, etc)

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [May 6, 2024, 4:35am UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/5 "2024-05-06T04:35:56Z")

</div>

I'd love to see Rust have support for implicit struct reborrowing to make it easier to use structs that neatly wrap up nasty borrow splitting problems, or constrain how `&mut` can be used (`Pin<&mut...` being an example of that, of sorts).

> [@Jules-Bertholet](#):
>
> - **New:** if `Super` implements `Reborrow` but not `Copy`, `arg` is inaccessible only until `Super`'s lifetime ends.

What exactly does “`Super`'s lifetime” mean here? A lifetime parameter? What if `Super` has multiple lifetime parameters, and some of them are used in a way which requires them to be as long as the original, or are invariant — or both? For example,

```rust
pub(crate) struct Foo<'sh, 'mu> {
    buf: &'mu mut Vec<&'sh str>,
    cur: &'sh str,
}

```

Here the `'sh` lifetime is used with references that do not need the reborrow treatment, and also _cannot_ be shortened without unsoundness, since it is used in an invariant position. So, the reborrow feature should be able to shorten `'mu` as needed while leaving `'sh` alone.

Perhaps the variance of the lifetime parameters could imply what to do? Or perhaps `Reborrow` could explicitly specify what lifetime it affects:

```rust
impl<'sh, 'mu> Reborrow<'mu> for Foo<'sh, 'mu> {}

```

…no, that would give the lifetime parameter on `Reborrow` weird magic semantics. What if the reborrow output is specified as a GAT, while still not having any `fn reborrow()`?

```rust
impl<'sh, 'mu> Reborrow for Foo<'sh, 'mu> {
    type Output<'mu2> = Foo<'sh, 'mu2> where 'mu: 'mu2;
}

```

It would be a compile error for `Reborrow::Output` to be anything that is not a supertype of `Self`.

---

<div class="post-metadata">

**Author:** ![Jules-Bertholet](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jules-bertholet/32/10671_2.png) [@Jules-Bertholet](https://internals.rust-lang.org/u/Jules-Bertholet)\
**Post date:** [May 6, 2024, 5:21am UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/6 "2024-05-06T05:21:55Z")

</div>

> [@kpreid](#):
>
> What exactly does “`Super`'s lifetime” mean here?

What I was originally going for was "the longest `'a` such that `Super: 'a` holds". But I'm now realizing that this doesn't work. For `struct Foo<'a>(&'a mut i32, &'static mut i32);`, the lifetime of `Foo<'a>` is `'a`, but it must remain borrowed for `'static`.

* * *

# Revised design

Here's what I think we have to do instead. First, we redefine `Reborrow` like so:

```rust
#[lang = "reborrow"]
#[marker]
pub trait Reborrow<'a> {}

impl<'a, T: Copy> Reborrow<'a> for T { }
impl<'a, T: ?Sized> Reborrow<'a> for &'a mut T { }
impl<'short, 'long: 'short, T: Reborrow<'short>> Reborrow<'long> for T { }

```

- A type can implement `Reborrow<'a>` iff the types of all its fields implement `Reborrow<'a>`.
- Other requirements are unchanged.

## New semantics

For any two types `Super` and `Sub`, such that `Super` is a supertype of `Sub`:

```rust
fn foo(arg: Sub) {
    let local: Super = arg;
    // HERE
}

```

At the point marked `HERE`:

- If `Sub` implements `Copy`, `arg` remains fully accessible.
- If `Sub` implements neither `Copy` nor `Reborrow`, `arg` is permanently inaccessible.
- **New:** if `Sub` implements `Reborrow` (lifetime does not matter) but not `Copy`, and `Super: Reborrow<'a>` (pick the shortest `'a` for which this holds), `arg` is inaccessible for `'a`.

* * *

> [@kpreid](#):
>
> Here the `'sh` lifetime is used with references that do not need the reborrow treatment, and also _cannot_ be shortened without unsoundness, since it is used in an invariant position.

Because `Reborrow`'s semantics are defined in terms of subtyping, we get proper handling of invariance "for free".

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [May 6, 2024, 7:04am UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/7 "2024-05-06T07:04:09Z")

</div>

> [@Jules-Bertholet](#):
>
> `UnsafeCell<T>` is invariant in `T`, so an implementation of `Reborrow` would be pointless (as there is no supertype to reborrow it as).

Ralf at least has expressed an interest in interior mutability types which implement `Copy`. Anyway, the thing that tickled my mind was a dead-end, so nevermind for now I guess.

> [@Jules-Bertholet](#):
>
> Probably like the latter? Since it's strictly more useful.

> [@Jules-Bertholet](#):
>
> What I was originally going for was "the longest `'a` such that `Super: 'a` holds". But I'm now realizing that this doesn't work.

More generally, actual reborrowing is quite complicated. And while informed by lifetimes, lifetimes aren't the whole story, as (for one example) [uses can make the (re-)borrow of a place shorter than the associated lifetime.](https://rust-lang.github.io/rfcs/2094-nll.html#borrow-checker-phase-1-computing-loans-in-scope)\[1\] Not to mention lifetimes being flow-control sensitive more generally in Polonius.

I think a desugaring-based definition would be more tractable and explainable than some entirely new mechanism.

* * *

1. [Polonius version](https://smallcultfollowing.com/babysteps/blog/2018/04/27/an-alias-based-formulation-of-the-borrow-checker/#refining-constraint-propagation-with-liveness)

---

<div class="post-metadata">

**Author:** ![elidupree](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elidupree/32/4304_2.png) [@elidupree](https://internals.rust-lang.org/u/elidupree)\
**Post date:** [May 6, 2024, 10:40am UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/8 "2024-05-06T10:40:12Z")

</div>

> [@Jules-Bertholet](#):
>
> [RFC 2364](https://github.com/dhardy/rfcs/blob/reborrow/text/0000-formalise-reborrows.md) (postponed) proposed to formalize a `Reborrow` trait. But the definition of the trait had a problem:
> 
> > We introduce the following trait, as member of `std::marker`:
> > 
> > ```rust
> > trait Reborrow { fn reborrow(&self) -> ???; }
> > 
> > ```
> > 
> > Unfortunately the return type of `fn reborrow` isn't representable in general; the return type must be `Self` but with different lifetime(s) (and note that there will be multiple lifetimes if the type has multiple fields with lifetimes). It is not possible to use an associated type `type Result: ???` because the return type includes a lifetime (or multiple) bound by the caller.
> 
> Let's try again.

This must have been written before GATs were stabilized. Could it perhaps be done with GATs now? This could also take care of the "reborrowing to &T" scenario. GATs are a bit unwieldy, but you could do it like this [EDIT: wait, I think this isn't quite right, or maybe there is a simpler way to do it. But maybe this will give people ideas]:

```rust
trait ReborrowOutput {
  type Output<'a> where Self: 'a;
}
trait Reborrow<'a, Output: ReborrowOutput> {
  fn reborrow<'b>(&'a mut self) -> Output::Output<'b> where 'a: 'b;
}

```

(full code with impls in [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=08fba4b94f43b16f16dc379bf04c8cd3) )

(Might be preferable if you could specify that Output should be covariant in 'a, but I'm not sure it would be a problem at use-sites because `reborrow` is explicitly able to shorten the lifetime anyway)

---

<div class="post-metadata">

**Author:** ![DasLixou](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/daslixou/32/12132_2.png) [@DasLixou](https://internals.rust-lang.org/u/DasLixou)\
**Post date:** [May 8, 2024, 3:55pm UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/9 "2024-05-08T15:55:42Z")

</div>

I tried your idea but putting it in one trait and using it on the original example of the first RFC: [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dc289e319ac1cf53c2adf8176e4053da)

---

<div class="post-metadata">

**Author:** ![jdahlstrom](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jdahlstrom/32/3351_2.png) [@jdahlstrom](https://internals.rust-lang.org/u/jdahlstrom)\
**Post date:** [May 8, 2024, 6:53pm UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/10 "2024-05-08T18:53:58Z")

</div>

I don't think any reborrowing actually happens in your code, because shared references are `Copy`. Indeed it's possible to remove the `'long` and `'short` lifetimes and [the code (which is now essentially the identity function) still compiles!](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6a9473bb76e9d4a6ba031cc296c9222c)

To force reborrowing, you have to use exclusive references, and [then the code won't compile ☹](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5fc79f8467ecb323c0aa633d0e3b46a6)

---

<div class="post-metadata">

**Author:** ![DasLixou](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/daslixou/32/12132_2.png) [@DasLixou](https://internals.rust-lang.org/u/DasLixou)\
**Post date:** [May 8, 2024, 7:29pm UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/11 "2024-05-08T19:29:43Z")

</div>

oh. you are right. sorry 😓

---

<div class="post-metadata">

**Author:** ![DasLixou](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/daslixou/32/12132_2.png) [@DasLixou](https://internals.rust-lang.org/u/DasLixou)\
**Post date:** [May 9, 2024, 5:44pm UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/12 "2024-05-09T17:44:43Z")

</div>

don't see it mentioned here anywhere and just found this: [reborrow - Rust](https://docs.rs/reborrow/0.5.5/reborrow/) (Am I allowed to post links?)

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [August 7, 2024, 5:45pm UTC](https://internals.rust-lang.org/t/reborrow-trait/20774/13 "2024-08-07T17:45:38Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
