]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_typeck/check/mod.rs
Auto merge of #43737 - GuillaumeGomez:duplicate-method, r=eddyb
[rust.git] / src / librustc_typeck / check / mod.rs
index 73e8bf305af4bafd6bfa1bddebe9be7525ee68c6..b9a9a954006572b7ea2433582460ad3ffa0e8f0d 100644 (file)
@@ -4229,8 +4229,8 @@ fn check_block_with_expected(&self,
         ty
     }
 
-    /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
-    /// `fn main` if it is a method, `None` otherwise.
+    /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
+    /// suggetion can be made, `None` otherwise.
     pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
         // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
         // `while` before reaching it, as block tail returns are not available in them.
@@ -4241,14 +4241,23 @@ pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
                 name, node: hir::ItemFn(ref decl, ..), ..
             }) = parent {
                 decl.clone().and_then(|decl| {
-                    // This is less than ideal, it will not present the return type span on any
-                    // method called `main`, regardless of whether it is actually the entry point.
-                    Some((decl, name == Symbol::intern("main")))
+                    // This is less than ideal, it will not suggest a return type span on any
+                    // method called `main`, regardless of whether it is actually the entry point,
+                    // but it will still present it as the reason for the expected type.
+                    Some((decl, name != Symbol::intern("main")))
                 })
             } else if let Node::NodeTraitItem(&hir::TraitItem {
                 node: hir::TraitItemKind::Method(hir::MethodSig {
                     ref decl, ..
                 }, ..), ..
+            }) = parent {
+                decl.clone().and_then(|decl| {
+                    Some((decl, true))
+                })
+            } else if let Node::NodeImplItem(&hir::ImplItem {
+                node: hir::ImplItemKind::Method(hir::MethodSig {
+                    ref decl, ..
+                }, ..), ..
             }) = parent {
                 decl.clone().and_then(|decl| {
                     Some((decl, false))
@@ -4275,11 +4284,8 @@ pub fn suggest_mismatched_types_on_tail(&self,
                                             blk_id: ast::NodeId) {
         self.suggest_missing_semicolon(err, expression, expected, cause_span);
 
-        if let Some((fn_decl, is_main)) = self.get_fn_decl(blk_id) {
-            // `fn main()` must return `()`, do not suggest changing return type
-            if !is_main {
-                self.suggest_missing_return_type(err, &fn_decl, found);
-            }
+        if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
+            self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
         }
     }
 
@@ -4335,20 +4341,37 @@ fn suggest_missing_semicolon(&self,
     fn suggest_missing_return_type(&self,
                                    err: &mut DiagnosticBuilder<'tcx>,
                                    fn_decl: &hir::FnDecl,
-                                   ty: Ty<'tcx>) {
-
-        // Only recommend changing the return type for methods that
+                                   expected: Ty<'tcx>,
+                                   found: Ty<'tcx>,
+                                   can_suggest: bool) {
+        // Only suggest changing the return type for methods that
         // haven't set a return type at all (and aren't `fn main()` or an impl).
-        if let &hir::FnDecl {
-            output: hir::FunctionRetTy::DefaultReturn(span), ..
-        } = fn_decl {
-            if ty.is_suggestable() {
+        match (&fn_decl.output, found.is_suggestable(), can_suggest) {
+            (&hir::FunctionRetTy::DefaultReturn(span), true, true) => {
                 err.span_suggestion(span,
                                     "try adding a return type",
-                                    format!("-> {} ", ty));
-            } else {
+                                    format!("-> {} ", found));
+            }
+            (&hir::FunctionRetTy::DefaultReturn(span), false, true) => {
                 err.span_label(span, "possibly return type missing here?");
             }
+            (&hir::FunctionRetTy::DefaultReturn(span), _, _) => {
+                // `fn main()` must return `()`, do not suggest changing return type
+                err.span_label(span, "expected `()` because of default return type");
+            }
+            (&hir::FunctionRetTy::Return(ref ty), _, _) => {
+                // Only point to return type if the expected type is the return type, as if they
+                // are not, the expectation must have been caused by something else.
+                debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.node);
+                let sp = ty.span;
+                let ty = AstConv::ast_ty_to_ty(self, ty);
+                debug!("suggest_missing_return_type: return type sty {:?}", ty.sty);
+                debug!("suggest_missing_return_type: expected type sty {:?}", ty.sty);
+                if ty.sty == expected.sty {
+                    err.span_label(sp, format!("expected `{}` because of return type",
+                                               expected));
+                }
+            }
         }
     }