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

pin_project cannot be used with structs that hold mutable references #226

Closed
Ekleog opened this issue May 22, 2020 · 4 comments
Closed

pin_project cannot be used with structs that hold mutable references #226

Ekleog opened this issue May 22, 2020 · 4 comments
Labels
C-question Category: A question C-upstream-bug Category: This is a bug of compiler or dependencies (the fix may require action in the upstream)

Comments

@Ekleog
Copy link

Ekleog commented May 22, 2020

Hello,

I just tried using pin-project, as it looks like a really nice helper!

However, while doing so, I hit a wall: with pin-project = "0.4.17",

#[pin_project::pin_project]
pub struct Foo<'a, R> {
    buf: &'a mut [u8],

    #[pin]
    stuff: R,
}

impl<'a, R> Foo<'a, R> {
    fn foo(self: std::pin::Pin<&mut Self>) {
        let this = self.project();
        *this.buf = &mut this.buf[1..];
    }
}

fn main() {
}

fails to compile with this error message:

   Compiling foo v0.1.0 (/tmp/foo)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'pin in function call due to conflicting requirements
  --> src/main.rs:11:25
   |
11 |         let this = self.project();
   |                         ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 10:5...
  --> src/main.rs:10:5
   |
10 | /     fn foo(self: std::pin::Pin<&mut Self>) {
11 | |         let this = self.project();
12 | |         *this.buf = &mut this.buf[1..];
13 | |     }
   | |_____^
note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the impl at 9:6...
  --> src/main.rs:9:6
   |
9  | impl<'a, R> Foo<'a, R> {
   |      ^^
note: ...so that the types are compatible
  --> src/main.rs:11:25
   |
11 |         let this = self.project();
   |                         ^^^^^^^
   = note: expected  `std::pin::Pin<&mut Foo<'_, R>>`
              found  `std::pin::Pin<&mut Foo<'a, R>>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0495`.
error: could not compile `foo`.

Weirdly enough, replacing &'a mut by &'a works, so I'd guess something has been implemented specifically for &'a but hasn't been implemented for &'a mut?

Do you think it'd be possible to handle this in pin-project, or is it something that can't be fixed and I should just not use it? :)

@taiki-e
Copy link
Owner

taiki-e commented May 22, 2020

Hmm... I could reproduce this without pin-project (playground):

pub struct Foo<'a> {
    buf: &'a mut [u8],
}

impl<'a> Foo<'a> {
    fn foo(self: std::pin::Pin<&mut Self>) {
        self.buf = &mut self.buf[1..];
    }
}

I guess this related to rust-lang/rust#54934, but I'll look into this more.

@taiki-e
Copy link
Owner

taiki-e commented May 22, 2020

Ok, this looks like rust-lang/rust#72337 and can be fixed by adding lifetime 'a to std::pin::Pin<&mut Self>:

playground

  impl<'a, R> Foo<'a, R> {
-     fn foo(self: std::pin::Pin<&mut Self>) {
+     fn foo(self: std::pin::Pin<&'a mut Self>) {
          let this = self.project();
          *this.buf = &mut this.buf[1..];
      }
  }

@taiki-e taiki-e added C-question Category: A question C-upstream-bug Category: This is a bug of compiler or dependencies (the fix may require action in the upstream) labels May 22, 2020
@taiki-e taiki-e closed this as completed May 22, 2020
@Ekleog
Copy link
Author

Ekleog commented May 22, 2020

Oh. You're right, this isn't related to pin-project at all, sorry for having bothered you with it!

This being said, your solution unfortunately requires the Pin to be borrowed for the lifetime of the whole struct, which isn't the API I'm looking for, but I'm going to raise that point with the compiler directly.

Thank you! :D

@taiki-e
Copy link
Owner

taiki-e commented May 22, 2020

I also commented on rust-lang/rust#72477, but this way should fix it completely:

playground

#[pin_project::pin_project]
pub struct A<'a, R> {
    buf: &'a mut [u8],

    #[pin]
    stuff: R,
}

impl<'a> Foo<'a> {
    fn foo(mut self: std::pin::Pin<&mut Self>) {
        let this = self.project();
        let (_, rest) = std::mem::replace(&mut *this.buf, &mut []).split_at_mut(1);
        *this.buf = rest;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-question Category: A question C-upstream-bug Category: This is a bug of compiler or dependencies (the fix may require action in the upstream)
Projects
None yet
Development

No branches or pull requests

2 participants