diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2402d0eefde48..0d7f2f264c96c 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2121,6 +2121,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { _ => false, }; + // Only skip `Self`, `&Self` and `&mut Self`, + // and to handle other `self`s like normal arguments. + let mut skip = 0; + // In accordance with the rules for lifetime elision, we can determine // what region to use for elision in the output type in two ways. // First (determined here), if `self` is by-reference, then the @@ -2154,19 +2158,26 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { false }; - if let hir::TyKind::Rptr(lifetime_ref, ref mt) = inputs[0].node { - 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) { - let scope = Scope::Elision { - elide: Elide::Exact(lifetime), - s: self.scope, - }; - self.with(scope, |_, this| this.visit_ty(output)); - return; + match inputs[0].node { + hir::TyKind::Rptr(lifetime_ref, ref mt) => { + 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) { + let scope = Scope::Elision { + elide: Elide::Exact(lifetime), + s: self.scope, + }; + self.with(scope, |_, this| this.visit_ty(output)); + return; + } + skip = 1; } } } + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) if is_self_ty(path.res) => { + skip = 1; + } + _ => {} } } @@ -2178,7 +2189,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let arg_lifetimes = inputs .iter() .enumerate() - .skip(has_self as usize) + .skip(skip) .map(|(i, input)| { let mut gather = GatherLifetimes { map: self.map, diff --git a/src/test/ui/self/arbitrary_self_types_inexact_lifetime.rs b/src/test/ui/self/arbitrary_self_types_inexact_lifetime.rs new file mode 100644 index 0000000000000..6d526b16c2504 --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_inexact_lifetime.rs @@ -0,0 +1,14 @@ +#![feature(arbitrary_self_types)] + +#[derive(Debug)] +struct Foo; + +impl Foo { + fn a(self: &Box, f: &Foo) -> &Foo { f } //~ ERROR E0106 + + fn b(self: &Box, f: &Foo) -> &Box { self } //~ ERROR E0106 + + fn c(this: &Box, f: &Foo) -> &Foo { f } //~ ERROR E0106 +} + +fn main() {} diff --git a/src/test/ui/self/arbitrary_self_types_inexact_lifetime.stderr b/src/test/ui/self/arbitrary_self_types_inexact_lifetime.stderr new file mode 100644 index 0000000000000..214d341d7ef45 --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_inexact_lifetime.stderr @@ -0,0 +1,27 @@ +error[E0106]: missing lifetime specifier + --> $DIR/arbitrary_self_types_inexact_lifetime.rs:7:39 + | +LL | fn a(self: &Box, f: &Foo) -> &Foo { f } + | ^ expected lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `self` or `f` + +error[E0106]: missing lifetime specifier + --> $DIR/arbitrary_self_types_inexact_lifetime.rs:9:39 + | +LL | fn b(self: &Box, f: &Foo) -> &Box { self } + | ^ expected lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `self` or `f` + +error[E0106]: missing lifetime specifier + --> $DIR/arbitrary_self_types_inexact_lifetime.rs:11:39 + | +LL | fn c(this: &Box, f: &Foo) -> &Foo { f } + | ^ expected lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `this` or `f` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/self/arbitrary_self_types_lifetime.rs b/src/test/ui/self/arbitrary_self_types_lifetime.rs new file mode 100644 index 0000000000000..4c27a963578b8 --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_lifetime.rs @@ -0,0 +1,80 @@ +#![feature(arbitrary_self_types)] + +use std::pin::Pin; + +#[derive(Debug)] +struct Foo; +#[derive(Debug)] +struct Bar<'a>(&'a Foo); + +impl std::ops::Deref for Bar<'_> { + type Target = Foo; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Foo { + fn a(&self) -> Bar<'_> { + Bar(self) + } + + fn b(c: &Self) -> Bar<'_> { + Bar(c) + } + + fn c(self: Bar<'_>) -> Bar<'_> { + self + } + + fn d(e: Bar<'_>) -> Bar<'_> { + e + } + + fn e(self: &Self) -> Bar<'_> { + Bar(self) + } + + fn f(self: Bar<'_>) -> impl std::fmt::Debug { + self + //~^ ERROR cannot infer an appropriate lifetime + } + + fn g(self: Bar<'_>) -> impl std::fmt::Debug + '_ { + self + } +} + +impl<'a> Bar<'a> { + fn a(self: Bar<'a>, f: &Foo) -> (Bar<'a>, &Foo) { (self, f) } + fn b(self: Self, f: &Foo) -> (Bar<'a>, &Foo) { (self, f) } + fn c(self: Bar<'a>, f: &Foo) -> (Self, &Foo) { (self, f) } +} + +impl Bar<'_> { + fn e(self: Self, f: &Foo) -> (Self, &Foo) { (self, f) } +} + +struct Baz { + field: T, +} + +impl Baz { + fn field(self: Pin<&mut Self>) -> Pin<&mut T> { + let this = Pin::get_mut(self); + Pin::new(&mut this.field) + } +} + +fn main() { + let foo = Foo; + { foo.a() }; + { Foo::b(&foo) }; + { Bar(&foo).c() }; + { Foo::d(Bar(&foo)) }; + { foo.e() }; + { Bar(&foo).f() }; + { Bar(&foo).g() }; + let mut baz = Baz { field: 0u8 }; + { Pin::new(&mut baz).field() }; +} diff --git a/src/test/ui/self/arbitrary_self_types_lifetime.stderr b/src/test/ui/self/arbitrary_self_types_lifetime.stderr new file mode 100644 index 0000000000000..50a45180e0b64 --- /dev/null +++ b/src/test/ui/self/arbitrary_self_types_lifetime.stderr @@ -0,0 +1,23 @@ +error: cannot infer an appropriate lifetime + --> $DIR/arbitrary_self_types_lifetime.rs:39:9 + | +LL | fn f(self: Bar<'_>) -> impl std::fmt::Debug { + | -------------------- this return type evaluates to the `'static` lifetime... +LL | self + | ^^^^ ...but this borrow... + | +note: ...can't outlive the anonymous lifetime #1 defined on the method body at 38:5 + --> $DIR/arbitrary_self_types_lifetime.rs:38:5 + | +LL | / fn f(self: Bar<'_>) -> impl std::fmt::Debug { +LL | | self +LL | | +LL | | } + | |_____^ +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 38:5 + | +LL | fn f(self: Bar<'_>) -> impl std::fmt::Debug + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error +