about summary refs log tree commit diff
diff options
context:
space:
mode:
authorcsmoe <csmoe@msn.com>2020-05-16 16:08:56 +0800
committercsmoe <csmoe@msn.com>2020-05-16 17:05:20 +0800
commit633e4aafe65cd424cf6c8076869df1b49a4e0ec4 (patch)
tree0b59ee06b9f7af73547f49aeb34274ab3c14ce15
parent008d90a66a30bc8ff498f8ad47dea315c1853a75 (diff)
downloadrust-633e4aafe65cd424cf6c8076869df1b49a4e0ec4.tar.gz
rust-633e4aafe65cd424cf6c8076869df1b49a4e0ec4.zip
suggest on Self return type
-rw-r--r--src/librustc_typeck/check/mod.rs67
-rw-r--r--src/test/ui/async-await/issue-69276.rs12
2 files changed, 43 insertions, 36 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 57fdb03250e..0906c25baef 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 224b76e2d90..00000000000
--- 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() {}