From 29a41f0d86b82c2731cc2ab8c8a26272e773e4c3 Mon Sep 17 00:00:00 2001
From: csmoe <csmoe@msn.com>
Date: Mon, 11 May 2020 14:24:57 +0800
Subject: [PATCH 1/5] add ui test for issue-69276

---
 src/librustc_typeck/check/mod.rs           |  6 +++++-
 src/test/ui/async-await/issue-69276.rs     | 12 ++++++++++++
 src/test/ui/async-await/issue-69276.stderr |  8 ++++++++
 3 files changed, 25 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/async-await/issue-69276.rs
 create mode 100644 src/test/ui/async-await/issue-69276.stderr

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 956e09ec52b4a..57fdb03250e7a 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1659,6 +1659,7 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
 
     let prohibit_opaque = match item.kind {
         ItemKind::OpaqueTy(hir::OpaqueTy {
+            bounds,
             origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
             ..
         }) => {
@@ -1671,6 +1672,9 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
             };
             debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
 
+            for bound in bounds {
+                debug!("check_opaque_for_inheriting_lifetimes: {:?}", bound.trait_ref());
+            }
             tcx.predicates_of(def_id)
                 .predicates
                 .iter()
@@ -1695,7 +1699,7 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
             "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
              a parent scope",
             if is_async { "async fn" } else { "impl Trait" },
-        ),
+        )
         );
     }
 }
diff --git a/src/test/ui/async-await/issue-69276.rs b/src/test/ui/async-await/issue-69276.rs
new file mode 100644
index 0000000000000..224b76e2d903f
--- /dev/null
+++ b/src/test/ui/async-await/issue-69276.rs
@@ -0,0 +1,12 @@
+// edition:2018
+
+struct S<'a>(&'a i32);
+
+impl<'a> S<'a> {
+    async fn new(i: &'a i32) -> Self {
+    //~^ ERROR `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+        S(&22)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-69276.stderr b/src/test/ui/async-await/issue-69276.stderr
new file mode 100644
index 0000000000000..1ebfdfa8b54c5
--- /dev/null
+++ b/src/test/ui/async-await/issue-69276.stderr
@@ -0,0 +1,8 @@
+error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+  --> $DIR/issue-69276.rs:6:33
+   |
+LL |     async fn new(i: &'a i32) -> Self {
+   |                                 ^^^^
+
+error: aborting due to previous error
+

From 008d90a66a30bc8ff498f8ad47dea315c1853a75 Mon Sep 17 00:00:00 2001
From: csmoe <csmoe@msn.com>
Date: Sat, 16 May 2020 16:01:59 +0800
Subject: [PATCH 2/5] create error code E0754

---
 src/librustc_error_codes/error_codes.rs       |  1 +
 src/librustc_error_codes/error_codes/E0754.md | 29 +++++++++++++++++++
 2 files changed, 30 insertions(+)
 create mode 100644 src/librustc_error_codes/error_codes/E0754.md

diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index e01412bc21cfd..52d40fd0f2fa1 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -435,6 +435,7 @@ E0750: include_str!("./error_codes/E0750.md"),
 E0751: include_str!("./error_codes/E0751.md"),
 E0752: include_str!("./error_codes/E0752.md"),
 E0753: include_str!("./error_codes/E0753.md"),
+E0754: include_str!("./error_codes/E0754.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/src/librustc_error_codes/error_codes/E0754.md b/src/librustc_error_codes/error_codes/E0754.md
new file mode 100644
index 0000000000000..e7cea98201003
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0754.md
@@ -0,0 +1,29 @@
+`async fn`/`impl trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope.
+
+Erroneous code example:
+
+```compile_fail,E0754,edition2018
+struct S<'a>(&'a i32);
+
+impl<'a> S<'a> {
+    async fn new(i: &'a i32) -> Self {
+        S(&22)
+    }
+}
+```
+
+To fix this error we need to spell out `Self` to `S<'a>`:
+
+```edition2018
+struct S<'a>(&'a i32);
+
+impl<'a> S<'a> {
+    async fn new(i: &'a i32) -> S<'a> {
+        S(&22)
+    }
+}
+```
+
+This will be allowed at some point in the future, but the implementation is not yet complete. See the [issue-61949] for this limitation.
+
+[issue-61949]: https://github.com/rust-lang/rust/issues/61949

From 633e4aafe65cd424cf6c8076869df1b49a4e0ec4 Mon Sep 17 00:00:00 2001
From: csmoe <csmoe@msn.com>
Date: Sat, 16 May 2020 16:08:56 +0800
Subject: [PATCH 3/5] suggest on Self return type

---
 src/librustc_typeck/check/mod.rs       | 67 +++++++++++++++++---------
 src/test/ui/async-await/issue-69276.rs | 12 -----
 2 files changed, 43 insertions(+), 36 deletions(-)
 delete mode 100644 src/test/ui/async-await/issue-69276.rs

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 57fdb03250e7a..0906c25baef09 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1639,51 +1639,56 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
     struct ProhibitOpaqueVisitor<'tcx> {
         opaque_identity_ty: Ty<'tcx>,
         generics: &'tcx ty::Generics,
+        ty: Option<Ty<'tcx>>,
     };
 
     impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
         fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
             debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
+            self.ty = Some(t);
             if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) }
         }
 
         fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
             debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
             if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
-                return *index < self.generics.parent_count as u32;
+                let found_lifetime = *index < self.generics.parent_count as u32;
+                if !found_lifetime {
+                    self.ty = None;
+                }
+                return found_lifetime;
             }
 
             r.super_visit_with(self)
         }
     }
 
+    let mut visitor = ProhibitOpaqueVisitor {
+        opaque_identity_ty: tcx.mk_opaque(
+            def_id.to_def_id(),
+            InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
+        ),
+        generics: tcx.generics_of(def_id),
+        ty: None,
+    };
+    debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
+
     let prohibit_opaque = match item.kind {
         ItemKind::OpaqueTy(hir::OpaqueTy {
-            bounds,
             origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
             ..
-        }) => {
-            let mut visitor = ProhibitOpaqueVisitor {
-                opaque_identity_ty: tcx.mk_opaque(
-                    def_id.to_def_id(),
-                    InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
-                ),
-                generics: tcx.generics_of(def_id),
-            };
-            debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
-
-            for bound in bounds {
-                debug!("check_opaque_for_inheriting_lifetimes: {:?}", bound.trait_ref());
-            }
-            tcx.predicates_of(def_id)
-                .predicates
-                .iter()
-                .any(|(predicate, _)| predicate.visit_with(&mut visitor))
-        }
+        }) => tcx
+            .predicates_of(def_id)
+            .predicates
+            .iter()
+            .any(|(predicate, _)| predicate.visit_with(&mut visitor)),
         _ => false,
     };
+    debug!(
+        "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
+        prohibit_opaque, visitor
+    );
 
-    debug!("check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}", prohibit_opaque);
     if prohibit_opaque {
         let is_async = match item.kind {
             ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
@@ -1693,14 +1698,28 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
             _ => unreachable!(),
         };
 
-        tcx.sess.span_err(
+        let mut err = struct_span_err!(
+            tcx.sess,
             span,
-            &format!(
+            E0754,
             "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
              a parent scope",
             if is_async { "async fn" } else { "impl Trait" },
-        )
         );
+
+        if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
+            if snippet == "Self" {
+                if let Some(ty) = visitor.ty {
+                    err.span_suggestion(
+                        span,
+                        "consider spelling out the type instead",
+                        format!("{:?}", ty),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+        err.emit();
     }
 }
 
diff --git a/src/test/ui/async-await/issue-69276.rs b/src/test/ui/async-await/issue-69276.rs
deleted file mode 100644
index 224b76e2d903f..0000000000000
--- a/src/test/ui/async-await/issue-69276.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// edition:2018
-
-struct S<'a>(&'a i32);
-
-impl<'a> S<'a> {
-    async fn new(i: &'a i32) -> Self {
-    //~^ ERROR `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
-        S(&22)
-    }
-}
-
-fn main() {}

From 8841ede3648b5f12284dae850ec065374fd3af46 Mon Sep 17 00:00:00 2001
From: csmoe <csmoe@msn.com>
Date: Sat, 16 May 2020 17:10:08 +0800
Subject: [PATCH 4/5] bless suggestion on spell out

---
 src/librustc_error_codes/error_codes.rs                   | 2 +-
 .../error_codes/{E0754.md => E0755.md}                    | 7 +++++--
 src/librustc_typeck/check/mod.rs                          | 2 +-
 .../ui/async-await/issue-61949-self-return-type.stderr    | 5 +++--
 src/test/ui/async-await/issue-69276.stderr                | 8 --------
 src/test/ui/impl-trait/bound-normalization-fail.stderr    | 5 +++--
 6 files changed, 13 insertions(+), 16 deletions(-)
 rename src/librustc_error_codes/error_codes/{E0754.md => E0755.md} (70%)
 delete mode 100644 src/test/ui/async-await/issue-69276.stderr

diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index 52d40fd0f2fa1..6467561e509fa 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -435,7 +435,7 @@ E0750: include_str!("./error_codes/E0750.md"),
 E0751: include_str!("./error_codes/E0751.md"),
 E0752: include_str!("./error_codes/E0752.md"),
 E0753: include_str!("./error_codes/E0753.md"),
-E0754: include_str!("./error_codes/E0754.md"),
+E0755: include_str!("./error_codes/E0755.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/src/librustc_error_codes/error_codes/E0754.md b/src/librustc_error_codes/error_codes/E0755.md
similarity index 70%
rename from src/librustc_error_codes/error_codes/E0754.md
rename to src/librustc_error_codes/error_codes/E0755.md
index e7cea98201003..b6eb2e34ccfc5 100644
--- a/src/librustc_error_codes/error_codes/E0754.md
+++ b/src/librustc_error_codes/error_codes/E0755.md
@@ -1,4 +1,5 @@
-`async fn`/`impl trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope.
+`async fn`/`impl trait` return type cannot contain a projection
+or `Self` that references lifetimes from a parent scope.
 
 Erroneous code example:
 
@@ -24,6 +25,8 @@ impl<'a> S<'a> {
 }
 ```
 
-This will be allowed at some point in the future, but the implementation is not yet complete. See the [issue-61949] for this limitation.
+This will be allowed at some point in the future,
+but the implementation is not yet complete.
+See the [issue-61949] for this limitation.
 
 [issue-61949]: https://github.com/rust-lang/rust/issues/61949
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0906c25baef09..bd8f628957dc1 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1701,7 +1701,7 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
         let mut err = struct_span_err!(
             tcx.sess,
             span,
-            E0754,
+            E0755,
             "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
              a parent scope",
             if is_async { "async fn" } else { "impl Trait" },
diff --git a/src/test/ui/async-await/issue-61949-self-return-type.stderr b/src/test/ui/async-await/issue-61949-self-return-type.stderr
index 12fb77d8dd637..fe05754c83ff8 100644
--- a/src/test/ui/async-await/issue-61949-self-return-type.stderr
+++ b/src/test/ui/async-await/issue-61949-self-return-type.stderr
@@ -1,8 +1,9 @@
-error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+error[E0755]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
   --> $DIR/issue-61949-self-return-type.rs:11:40
    |
 LL |     pub async fn new(_bar: &'a i32) -> Self {
-   |                                        ^^^^
+   |                                        ^^^^ help: consider spelling out the type instead: `Foo<'a>`
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0754`.
diff --git a/src/test/ui/async-await/issue-69276.stderr b/src/test/ui/async-await/issue-69276.stderr
deleted file mode 100644
index 1ebfdfa8b54c5..0000000000000
--- a/src/test/ui/async-await/issue-69276.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
-  --> $DIR/issue-69276.rs:6:33
-   |
-LL |     async fn new(i: &'a i32) -> Self {
-   |                                 ^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr
index f5092044627f6..04b398f5b5283 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr
@@ -20,7 +20,7 @@ help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc
 LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
    |                         ^^^^^^^^^^^^
 
-error: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+error[E0755]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
   --> $DIR/bound-normalization-fail.rs:43:41
    |
 LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
@@ -42,4 +42,5 @@ LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0271, E0755.
+For more information about an error, try `rustc --explain E0271`.

From 9be635306cdf06dde62e2c1ebaadcdc33f44f45c Mon Sep 17 00:00:00 2001
From: csmoe <csmoe@msn.com>
Date: Fri, 22 May 2020 12:14:53 +0800
Subject: [PATCH 5/5] resolve error code e0760

---
 src/librustc_error_codes/error_codes.rs                     | 2 +-
 src/librustc_error_codes/error_codes/{E0755.md => E0760.md} | 2 +-
 src/librustc_typeck/check/mod.rs                            | 2 +-
 src/test/ui/async-await/issue-61949-self-return-type.stderr | 4 ++--
 src/test/ui/impl-trait/bound-normalization-fail.stderr      | 4 ++--
 5 files changed, 7 insertions(+), 7 deletions(-)
 rename src/librustc_error_codes/error_codes/{E0755.md => E0760.md} (94%)

diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index c0b16c22e4d98..97f0c16b4cfb2 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -437,7 +437,7 @@ E0751: include_str!("./error_codes/E0751.md"),
 E0752: include_str!("./error_codes/E0752.md"),
 E0753: include_str!("./error_codes/E0753.md"),
 E0754: include_str!("./error_codes/E0754.md"),
-E0755: include_str!("./error_codes/E0755.md"),
+E0760: include_str!("./error_codes/E0760.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/src/librustc_error_codes/error_codes/E0755.md b/src/librustc_error_codes/error_codes/E0760.md
similarity index 94%
rename from src/librustc_error_codes/error_codes/E0755.md
rename to src/librustc_error_codes/error_codes/E0760.md
index 0c289146176d9..e1dcfefebcd76 100644
--- a/src/librustc_error_codes/error_codes/E0755.md
+++ b/src/librustc_error_codes/error_codes/E0760.md
@@ -3,7 +3,7 @@ or `Self` that references lifetimes from a parent scope.
 
 Erroneous code example:
 
-```compile_fail,E0755,edition2018
+```compile_fail,E0760,edition2018
 struct S<'a>(&'a i32);
 
 impl<'a> S<'a> {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 200263728d934..4646e703496bb 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1690,7 +1690,7 @@ fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId,
             let mut err = struct_span_err!(
                 tcx.sess,
                 span,
-                E0755,
+                E0760,
                 "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
              a parent scope",
                 if is_async { "async fn" } else { "impl Trait" },
diff --git a/src/test/ui/async-await/issue-61949-self-return-type.stderr b/src/test/ui/async-await/issue-61949-self-return-type.stderr
index f57e097c1254d..4eeef871c5bfc 100644
--- a/src/test/ui/async-await/issue-61949-self-return-type.stderr
+++ b/src/test/ui/async-await/issue-61949-self-return-type.stderr
@@ -1,4 +1,4 @@
-error[E0755]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+error[E0760]: `async fn` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
   --> $DIR/issue-61949-self-return-type.rs:11:40
    |
 LL |     pub async fn new(_bar: &'a i32) -> Self {
@@ -6,4 +6,4 @@ LL |     pub async fn new(_bar: &'a i32) -> Self {
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0755`.
+For more information about this error, try `rustc --explain E0760`.
diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr
index c78d4c4a8fd12..03aba10cc79b4 100644
--- a/src/test/ui/impl-trait/bound-normalization-fail.stderr
+++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr
@@ -21,7 +21,7 @@ help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc
 LL |     fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> {
    |                         ^^^^^^^^^^^^
 
-error[E0755]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
+error[E0760]: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope
   --> $DIR/bound-normalization-fail.rs:43:41
    |
 LL |     fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> {
@@ -43,5 +43,5 @@ LL |     fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0271, E0755.
+Some errors have detailed explanations: E0271, E0760.
 For more information about an error, try `rustc --explain E0271`.