Manual reborrowing trait

I'm trying to create a custom Reborrow trait for general values, and put it in an associated type, like:

pub trait Reborrow<'a> {
    type Target;

    fn reborrow(&'a self) -> Self::Target;
}

impl<'a, 'b, T: ?Sized> Reborrow<'b> for &'a T {
    type Target = &'a T;

    #[inline(always)]
    fn reborrow(&'b self) -> Self::Target {
        *self
    }
}

trait Interner {
    type GenericArgsSlice<'a>: for<'b> Reborrow<'b, Target = Self::GenericArgsSlice<'b>>
    where
        Self: 'a;
}

struct GenericArg<'tcx>(&'tcx mut &'tcx ());

struct TyCtxt<'tcx>(&'tcx mut &'tcx ());

impl<'tcx> Interner for TyCtxt<'tcx> {
    type GenericArgsSlice<'a>
        = &'tcx [GenericArg<'tcx>]
    where
        Self: 'a;
}

There is also a version with GAT, but it fails even earlier.

This code does not compile:

error[E0477]: the type `TyCtxt<'tcx>` does not fulfill the required lifetime
  --> src/lib.rs:28:11
   |
17 |     type GenericArgsSlice<'a>: for<'b> Reborrow<'b, Target = Self::GenericArgsSlice<'b>>
   |     ------------------------------------------------------------------------------------ definition of `GenericArgsSlice` from trait
...
28 |         = &'tcx [GenericArg<'tcx>]
   |           ^^^^^^^^^^^^^^^^^^^^^^^^
   |
help: copy the `where` clause predicates from the trait
   |
29 -     where
30 -         Self: 'a;
29 +     where Self: 'a;
   |

The thing that causes the error is the combination of the Reborrow constraint and the Self: 'a constraint. If I remove either it works.

I don't understand why is that the case. I tried to let the compiler infer an implied Self: 'a in addition to the explicit by adding a dummy &'a Self parameter to Reborrow, but it didn't help.

Why does this fail, and is there a way to make it work while keeping the Self: 'a bound?

1 Like

I'm on mobile, so this will be a bit terse for now.

I think what you want is for the Self: 'a bound to be implicit under the for<'a>, like so:

For more on this technique and some explanation of the error, see this article:

I'm not sure it's exactly your use case, but it's at least related.

I tried that; it still gives me errors when I try to constrain GenericArgsSlice, plus I'm required to put the explicit bound because of the GAT, although I maybe can workaround that.

Also notable is that if I invert the dependency, that is Reborrow mentions GenericArgsSlice and not the opposite, it works, but unfortunately I have many such associated types and I don't want to have a trait for each.

Maybe parameterize Reborrow by T in addition to 'a, and make an empty GenericArgsSlice enum (and similar) to plug in to T? Also, I feel like a for<'a> supertrait bound might work better than a GAT. It’s a bit messy with the bounds, then, since you’d have to list out a bunch of supertrait bounds instead of associated types, but you can use those bounds almost as if they were associated types by making type aliases.

Check out the lender crate, it needs to do funky higher-kinded bounds. (lender is also very unsound atm, but I do like how it approaches bounds.)

When I've needed a reborrow trait, I typically use the family pattern, i.e.

pub trait Reborrow {
    type Rb<'a>;
    fn borrow<'a>(&'a mut self) -> Self::Rb<'a>;
    fn reborrow<'a, 'b>(rb: &'a mut Self::Rb<'b>) -> Self::Rb<'a>
}

(Of course, some lifetimes can be elided here.) A type is then reborrowable if it is <T as Reborrow>::Rb<'a> for some type T and lifetime 'a.

Given that the playground compiles, do you have an example that doesn't?