Repository: taiki-e/pin-project (Rust)

Issue:
Lifetime issue when `#[pin_project]` is used
[Playground link](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=44cfef1009b6d5fa949409383532d09e)

This code:
```rust
use pin_project::pin_project;

trait Bar<X> {
    type Y;
}

struct Example<A>(A);

impl<X, T> Bar<X> for Example<T> {
    type Y = Option<T>;
}

#[pin_project]
struct Foo<A, B> {
    x: <Example<A> as Bar<B>>::Y
}
```

Fails to compile with the error:
```
error[E0309]: the parameter type `A` may not live long enough
  --> src/main.rs:13:1
   |
13 | #[pin_project]
   | ^^^^^^^^^^^^^^
14 | struct Foo<A, B> {
   |            - help: consider adding an explicit lifetime bound...: `A: 'pin`
   |
note: ...so that the reference type `&'pin mut std::option::Option<A>` does not outlive the data it points at
  --> src/main.rs:13:1
   |
13 | #[pin_project]
   | ^^^^^^^^^^^^^^
   = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
```

It's possibly a compiler bug, because if I change `Option<A>` to `A` it compiles fine, which is really weird...

This is the expanded code produced by pin-project:
```rust
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
use pin_project::pin_project;
trait Bar<X> {
    type Y;
}
struct Example<A>(A);
impl<X, T> Bar<X> for Example<T> {
    type Y = Option<T>;
}
struct Foo<A, B> {
    x: <Example<A> as Bar<B>>::Y,
}
#[allow(clippy::mut_mut)]
#[allow(dead_code)]
struct __FooProjection<'pin, A, B> {
    x: &'pin mut (<Example<A> as Bar<B>>::Y),
}
#[allow(dead_code)]
struct __FooProjectionRef<'pin, A, B> {
    x: &'pin (<Example<A> as Bar<B>>::Y),
}
impl<A, B> Foo<A, B> {
    fn project<'pin>(self: ::core::pin::Pin<&'pin mut Self>) -> __FooProjection<'pin, A, B> {
        unsafe {
            let Foo { x } = self.get_unchecked_mut();
            __FooProjection { x }
        }
    }
    fn project_ref<'pin>(self: ::core::pin::Pin<&'pin Self>) -> __FooProjectionRef<'pin, A, B> {
        unsafe {
            let Foo { x } = self.get_ref();
            __FooProjectionRef { x }
        }
    }
}
#[allow(single_use_lifetimes)]
#[allow(non_snake_case)]
#[deny(safe_packed_borrows)]
fn __pin_project_assert_not_repr_packed_Foo<A, B>(val: &Foo<A, B>) {
    &val.x;
}
#[allow(non_snake_case)]
fn __unpin_scope_Foo() {
    struct __Foo<'pin, A, B> {
        __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin<'pin, (A, B)>,
    }
    impl<'pin, A, B> ::core::marker::Unpin for Foo<A, B> where __Foo<'pin, A, B>: ::core::marker::Unpin {}
}
trait FooMustNotImplDrop {}
#[allow(clippy::drop_bounds)]
impl<T: ::core::ops::Drop> FooMustNotImplDrop for T {}
#[allow(single_use_lifetimes)]
impl<A, B> FooMustNotImplDrop for Foo<A, B> {}
#[allow(single_use_lifetimes)]
impl<A, B> ::pin_project::__private::PinnedDrop for Foo<A, B> {
    unsafe fn drop(self: ::core::pin::Pin<&mut Self>) {}
}
```


Discussion:
And here is the result of reducing that expanded code:
```rust

trait Bar<X> {
    type Y;
}
struct Example<A>(A);
impl<X, T> Bar<X> for Example<T> {
    type Y = Option<T>;
}
struct Foo<A, B> {
    x: <Example<A> as Bar<B>>::Y,
}
struct __FooProjection<'pin, A, B> {
    x: &'pin mut <Example<A> as Bar<B>>::Y,
}
```
It looks like the compiler is giving the correct error here. From the [`infer_outlives` rfc](https://rust-lang.github.io/rfcs/2093-infer-outlives.html#where-explicit-annotations-would-still-be-required):


> In turn, if this associated type were used in a struct, where-clauses would be required. As we'll see in the reference-level explanation, this is a consequence of the fact that we do inference without regard for associated type normalization, but it makes for a relatively simple rule -- explicit where clauses are needed in the preseence of impls like the one above:

```rust
struct Foo<'a, T>
  where T: 'a // still required, not inferred from `field`
{
  field: <Vec<T> as MakeRef<'a>>::Type
}    
```

I think the solution is for `pin-project` to always generate `T: 'pin` for each type parameter `T`.
@Aaron1011 it might be safer to add this bound instead:
` where Foo<A, B>: 'pin`

This also seems to fix the problem.

```rust
trait Bar<X> {
    type Y;
}
struct Example<A>(A);
impl<X, T> Bar<X> for Example<T> {
    type Y = Option<T>;
}
struct Foo<A, B> {
    x: <Example<A> as Bar<B>>::Y,
}
struct __FooProjection<'pin, A, B> where Foo<A, B>: 'pin {
    x: &'pin mut <Example<A> as Bar<B>>::Y,
}
```

Just in case there are parameters which don't need to have that constraint, we can leave that to the compiler to figure out.
@Diggsey: That's a good idea - I'll do that instead.
Published 0.4.9 which fixes this issue.


Nice! 👍 



Patch:
diff --git a/pin-project-internal/src/pin_project/derive.rs b/pin-project-internal/src/pin_project/derive.rs
index 1ed1c569..30318f04 100644
--- a/pin-project-internal/src/pin_project/derive.rs
+++ b/pin-project-internal/src/pin_project/derive.rs
@@ -196,6 +196,9 @@ struct ProjectedType {
     lifetime: Lifetime,
     /// Generics of the projected type.
     generics: Generics,
+    /// `where` clause of the projected type. This has an additional
+    /// bound generated by `insert_lifetime_and_bound`
+    where_clause: WhereClause,
 }
 
 struct Context {
@@ -230,7 +233,16 @@ impl Context {
         let lifetime = Lifetime::new(&lifetime_name, Span::call_site());
 
         let mut proj_generics = generics.clone();
-        insert_lifetime(&mut proj_generics, lifetime.clone());
+        let ty_generics = generics.split_for_impl().1;
+        let ty_generics_as_generics = syn::parse_quote!(#ty_generics);
+        let pred = insert_lifetime_and_bound(
+            &mut proj_generics,
+            lifetime.clone(),
+            &ty_generics_as_generics,
+            ident.clone(),
+        );
+        let mut where_clause = generics.clone().make_where_clause().clone();
+        where_clause.predicates.push(pred);
 
         Ok(Self {
             proj: ProjectedType {
@@ -239,6 +251,7 @@ impl Context {
                 ref_ident: proj_ident(&ident, Immutable),
                 lifetime,
                 generics: proj_generics,
+                where_clause,
             },
             orig: OriginalType { attrs, vis, ident, generics },
             pinned_drop,
@@ -250,7 +263,7 @@ impl Context {
     fn parse_struct(&mut self, fields: &Fields) -> Result<TokenStream> {
         let (proj_pat, proj_init, proj_fields, proj_ref_fields) = match fields {
             Fields::Named(fields) => self.visit_named(fields)?,
-            Fields::Unnamed(fields) => self.visit_unnamed(fields, true)?,
+            Fields::Unnamed(fields) => self.visit_unnamed(fields)?,
             Fields::Unit => unreachable!(),
         };
 
@@ -259,7 +272,7 @@ impl Context {
         let proj_ref_ident = &self.proj.ref_ident;
         let vis = &self.proj.vis;
         let proj_generics = &self.proj.generics;
-        let where_clause = self.orig.generics.split_for_impl().2;
+        let where_clause = &self.proj.where_clause;
 
         // For tuple structs, we need to generate `(T1, T2) where Foo: Bar`
         // For non-tuple structs, we need to generate `where Foo: Bar { field1: T }`
@@ -268,7 +281,7 @@ impl Context {
                 (quote!(#where_clause #proj_fields), quote!(#where_clause #proj_ref_fields))
             }
             Fields::Unnamed(_) => {
-                (quote!(#proj_fields #where_clause), quote!(#proj_ref_fields #where_clause))
+                (quote!(#proj_fields #where_clause;), quote!(#proj_ref_fields #where_clause;))
             }
             Fields::Unit => unreachable!(),
         };
@@ -303,7 +316,7 @@ impl Context {
         let proj_ref_ident = &self.proj.ref_ident;
         let vis = &self.proj.vis;
         let proj_generics = &self.proj.generics;
-        let where_clause = self.orig.generics.split_for_impl().2;
+        let where_clause = &self.proj.where_clause;
 
         let mut proj_items = quote! {
             #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
@@ -344,7 +357,7 @@ impl Context {
         for Variant { ident, fields, .. } in variants {
             let (proj_pat, proj_body, proj_fields, proj_ref_fields) = match fields {
                 Fields::Named(fields) => self.visit_named(fields)?,
-                Fields::Unnamed(fields) => self.visit_unnamed(fields, false)?,
+                Fields::Unnamed(fields) => self.visit_unnamed(fields)?,
                 Fields::Unit => {
                     (TokenStream::new(), TokenStream::new(), TokenStream::new(), TokenStream::new())
                 }
@@ -422,7 +435,6 @@ impl Context {
     fn visit_unnamed(
         &mut self,
         FieldsUnnamed { unnamed: fields, .. }: &FieldsUnnamed,
-        is_struct: bool,
     ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> {
         let mut proj_pat = Vec::with_capacity(fields.len());
         let mut proj_body = Vec::with_capacity(fields.len());
@@ -460,11 +472,8 @@ impl Context {
 
         let proj_pat = quote!((#(#proj_pat),*));
         let proj_body = quote!((#(#proj_body),*));
-        let (proj_fields, proj_ref_fields) = if is_struct {
-            (quote!((#(#proj_fields),*);), quote!((#(#proj_ref_fields),*);))
-        } else {
-            (quote!((#(#proj_fields),*)), quote!((#(#proj_ref_fields),*)))
-        };
+        let (proj_fields, proj_ref_fields) =
+            (quote!((#(#proj_fields),*)), quote!((#(#proj_ref_fields),*)));
 
         Ok((proj_pat, proj_body, proj_fields, proj_ref_fields))
     }
diff --git a/pin-project-internal/src/utils.rs b/pin-project-internal/src/utils.rs
index b96aa569..1890afcf 100644
--- a/pin-project-internal/src/utils.rs
+++ b/pin-project-internal/src/utils.rs
@@ -61,6 +61,29 @@ pub(crate) fn determine_lifetime_name(
     }
 }
 
+/// Like `insert_lifetime`, but also generates a bound of the form
+/// `OriginalType<A, B>: 'lifetime`. Used when generating the definition
+/// of a projection type
+pub(crate) fn insert_lifetime_and_bound(
+    generics: &mut Generics,
+    lifetime: Lifetime,
+    orig_generics: &Generics,
+    orig_ident: Ident,
+) -> WherePredicate {
+    insert_lifetime(generics, lifetime.clone());
+
+    let orig_type: syn::Type = syn::parse_quote!(#orig_ident #orig_generics);
+    let mut punct = Punctuated::new();
+    punct.push(TypeParamBound::Lifetime(lifetime));
+
+    WherePredicate::Type(PredicateType {
+        lifetimes: None,
+        bounded_ty: orig_type,
+        colon_token: syn::token::Colon::default(),
+        bounds: punct,
+    })
+}
+
 /// Inserts a `lifetime` at position `0` of `generics.params`.
 pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) {
     if generics.lt_token.is_none() {


Test patch:
diff --git a/tests/no_infer_outlives.rs b/tests/no_infer_outlives.rs
new file mode 100644
index 00000000..6602b62c
--- /dev/null
+++ b/tests/no_infer_outlives.rs
@@ -0,0 +1,19 @@
+use pin_project::{pin_project, project};
+
+trait Bar<X> {
+    type Y;
+}
+
+struct Example<A>(A);
+
+impl<X, T> Bar<X> for Example<T> {
+    type Y = Option<T>;
+}
+
+#[pin_project]
+struct Foo<A, B> {
+    _x: <Example<A> as Bar<B>>::Y,
+}
+
+#[project]
+impl<A, B> Foo<A, B> {}