X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustc_typeck%2Fcheck%2Fmod.rs;h=b9a9a954006572b7ea2433582460ad3ffa0e8f0d;hb=2ac5f7d249e29ee48737359e0e6dd9e59701a568;hp=73e8bf305af4bafd6bfa1bddebe9be7525ee68c6;hpb=aaa14d1d20f3cc1104bb619f66c78a49762182ff;p=rust.git diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 73e8bf305af..b9a9a954006 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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)); + } + } } }