about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTaiki Endo <te316e89@gmail.com>2019-05-27 01:43:12 +0900
committerTaiki Endo <te316e89@gmail.com>2019-07-27 12:28:02 +0900
commite2eb957be0f6c31585c31815e6c423e7c1d75856 (patch)
tree5357078ae17f46674ca6f03014fab81d4b035fec
parent09e39897587dca70f0b15093d425a682c392349c (diff)
downloadrust-e2eb957be0f6c31585c31815e6c423e7c1d75856.tar.gz
rust-e2eb957be0f6c31585c31815e6c423e7c1d75856.zip
Allow lifetime elision in `Pin<&(mut) Self>`
-rw-r--r--src/librustc/middle/resolve_lifetime.rs29
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime.rs60
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs13
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr20
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs13
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr18
-rw-r--r--src/test/ui/self/self_lifetime.rs13
7 files changed, 165 insertions, 1 deletions
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index abb896a7c9b..0e99190c20c 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -2174,7 +2174,34 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 false
             };
 
-            if let hir::TyKind::Rptr(lifetime_ref, ref mt) = inputs[0].node {
+            let mut self_arg = &inputs[0].node;
+
+            // Apply `self: &(mut) Self` elision rules even if nested in `Pin`.
+            loop {
+                if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = *self_arg {
+                    if let Res::Def(DefKind::Struct, def_id) = path.res {
+                        if self.tcx.lang_items().pin_type() == Some(def_id) {
+                            if let Some(args) = path
+                                .segments
+                                .last()
+                                .and_then(|segment| segment.args.as_ref())
+                            {
+                                if args.args.len() == 1 {
+                                    if let GenericArg::Type(ty) = &args.args[0] {
+                                        self_arg = &ty.node;
+                                        // Keep dereferencing `self_arg` until we get to non-`Pin`
+                                        // types.
+                                        continue;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+
+            if let hir::TyKind::Rptr(lifetime_ref, ref mt) = *self_arg {
                 if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node {
                     if is_self_ty(path.res) {
                         if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime.rs
new file mode 100644
index 00000000000..668aaf7166a
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime.rs
@@ -0,0 +1,60 @@
+// compile-pass
+
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+struct Foo;
+
+impl Foo {
+    fn pin_ref(self: Pin<&Self>) -> Pin<&Self> { self }
+
+    fn pin_mut(self: Pin<&mut Self>) -> Pin<&mut Self> { self }
+
+    fn pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> Pin<Pin<Pin<&Self>>> { self }
+
+    fn pin_ref_impl_trait(self: Pin<&Self>) -> impl Clone + '_ { self }
+
+    fn b(self: Pin<&Foo>, f: &Foo) -> Pin<&Foo> { self }
+}
+
+type Alias<T> = Pin<T>;
+impl Foo {
+    fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+}
+
+struct Bar<T: Unpin, U: Unpin> {
+    field1: T,
+    field2: U,
+}
+
+impl<T: Unpin, U: Unpin> Bar<T, U> {
+    fn fields(self: Pin<&mut Self>) -> (Pin<&mut T>, Pin<&mut U>) {
+        let this = self.get_mut();
+        (Pin::new(&mut this.field1), Pin::new(&mut this.field2))
+    }
+}
+
+trait AsyncBufRead {
+    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>)
+        -> Poll<std::io::Result<&[u8]>>;
+}
+
+struct Baz(Vec<u8>);
+
+impl AsyncBufRead for Baz {
+    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>)
+        -> Poll<std::io::Result<&[u8]>>
+    {
+        Poll::Ready(Ok(&self.get_mut().0))
+    }
+}
+
+fn main() {
+    let mut foo = Foo;
+    { Pin::new(&foo).pin_ref() };
+    { Pin::new(&mut foo).pin_mut() };
+    { Pin::new(Pin::new(Pin::new(&foo))).pin_pin_pin_ref() };
+    { Pin::new(&foo).pin_ref_impl_trait() };
+    let mut bar = Bar { field1: 0u8, field2: 1u8 };
+    { Pin::new(&mut bar).fields() };
+}
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs
new file mode 100644
index 00000000000..ad8959727cb
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.rs
@@ -0,0 +1,13 @@
+// compile-fail
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR cannot infer an appropriate lifetime
+}
+
+fn main() {
+    { Pin::new(&Foo).f() };
+}
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
new file mode 100644
index 00000000000..5118280e7ec
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr
@@ -0,0 +1,20 @@
+error: cannot infer an appropriate lifetime
+  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:44
+   |
+LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
+   |                               ----------   ^^^^ ...but this borrow...
+   |                               |
+   |                               this return type evaluates to the `'static` lifetime...
+   |
+note: ...can't outlive the anonymous lifetime #1 defined on the method body at 8:5
+  --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:5
+   |
+LL |     fn f(self: Pin<&Self>) -> impl Clone { self }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 8:5
+   |
+LL |     fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
+   |                               ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
new file mode 100644
index 00000000000..3ed5e6bdd72
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
@@ -0,0 +1,13 @@
+// compile-fail
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0623
+
+    fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } //~ ERROR E0623
+}
+
+fn main() {}
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
new file mode 100644
index 00000000000..6e345b03056
--- /dev/null
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
@@ -0,0 +1,18 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:46
+   |
+LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+   |                              ----     ----   ^ ...but data from `f` is returned here
+   |                              |
+   |                              this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:76
+   |
+LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+   |                               ----              -----------------          ^ ...but data from `f` is returned here
+   |                               |
+   |                               this parameter and the return type are declared with different lifetimes...
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/self/self_lifetime.rs b/src/test/ui/self/self_lifetime.rs
new file mode 100644
index 00000000000..a3163ade040
--- /dev/null
+++ b/src/test/ui/self/self_lifetime.rs
@@ -0,0 +1,13 @@
+// compile-pass
+
+struct Foo<'a>(&'a ());
+impl<'a> Foo<'a> {
+    fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
+}
+
+type Alias = Foo<'static>;
+impl Alias {
+    fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
+}
+
+fn main() {}