Allow lifetime elision in Pin<&(mut) Self>
This commit is contained in:
parent
09e3989758
commit
e2eb957be0
7 changed files with 165 additions and 1 deletions
|
@ -2174,7 +2174,34 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
false
|
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 let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node {
|
||||||
if is_self_ty(path.res) {
|
if is_self_ty(path.res) {
|
||||||
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
|
if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
|
||||||
|
|
60
src/test/ui/self/arbitrary_self_types_pin_lifetime.rs
Normal file
60
src/test/ui/self/arbitrary_self_types_pin_lifetime.rs
Normal file
|
@ -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() };
|
||||||
|
}
|
|
@ -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() };
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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() {}
|
|
@ -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
|
||||||
|
|
13
src/test/ui/self/self_lifetime.rs
Normal file
13
src/test/ui/self/self_lifetime.rs
Normal file
|
@ -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() {}
|
Loading…
Reference in a new issue