@@ -4796,16 +4796,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
47964796 // `consider_hint_about_removing_semicolon` will point at the last expression
47974797 // if it were a relevant part of the error. This improves usability in editors
47984798 // that highlight errors inline.
4799- let sp = if let Some ( ( decl, _ ) ) = self . get_fn_decl ( blk. id ) {
4800- decl. output . span ( )
4799+ let ( sp , fn_span ) = if let Some ( ( decl, ident ) ) = self . get_parent_fn_decl ( blk. id ) {
4800+ ( decl. output . span ( ) , Some ( ident . span ) )
48014801 } else {
4802- blk. span
4802+ ( blk. span , None )
48034803 } ;
48044804 coerce. coerce_forced_unit ( self , & self . misc ( sp) , & mut |err| {
48054805 if let Some ( expected_ty) = expected. only_has_type ( self ) {
4806- self . consider_hint_about_removing_semicolon ( blk,
4807- expected_ty,
4808- err) ;
4806+ self . consider_hint_about_removing_semicolon ( blk, expected_ty, err) ;
4807+ }
4808+ if let Some ( fn_span) = fn_span {
4809+ err. span_label (
4810+ fn_span,
4811+ "this function's body doesn't return the expected type" ,
4812+ ) ;
48094813 }
48104814 } , false ) ;
48114815 }
@@ -4830,59 +4834,69 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
48304834 ty
48314835 }
48324836
4837+ /// Given a function block's `NodeId`, return its `FnDecl` , `None` otherwise.
4838+ fn get_parent_fn_decl ( & self , blk_id : ast:: NodeId ) -> Option < ( hir:: FnDecl , ast:: Ident ) > {
4839+ let parent = self . tcx . hir ( ) . get ( self . tcx . hir ( ) . get_parent ( blk_id) ) ;
4840+ self . get_node_fn_decl ( parent) . map ( |( fn_decl, ident , _) | ( fn_decl, ident) )
4841+ }
4842+
4843+ /// Given a function `Node`, return its `FnDecl` , `None` otherwise.
4844+ fn get_node_fn_decl ( & self , node : Node ) -> Option < ( hir:: FnDecl , ast:: Ident , bool ) > {
4845+ if let Node :: Item ( & hir:: Item {
4846+ ident, node : hir:: ItemKind :: Fn ( ref decl, ..) , ..
4847+ } ) = node {
4848+ decl. clone ( ) . and_then ( |decl| {
4849+ // This is less than ideal, it will not suggest a return type span on any
4850+ // method called `main`, regardless of whether it is actually the entry point,
4851+ // but it will still present it as the reason for the expected type.
4852+ Some ( ( decl, ident, ident. name != Symbol :: intern ( "main" ) ) )
4853+ } )
4854+ } else if let Node :: TraitItem ( & hir:: TraitItem {
4855+ ident, node : hir:: TraitItemKind :: Method ( hir:: MethodSig {
4856+ ref decl, ..
4857+ } , ..) , ..
4858+ } ) = node {
4859+ decl. clone ( ) . and_then ( |decl| {
4860+ Some ( ( decl, ident, true ) )
4861+ } )
4862+ } else if let Node :: ImplItem ( & hir:: ImplItem {
4863+ ident, node : hir:: ImplItemKind :: Method ( hir:: MethodSig {
4864+ ref decl, ..
4865+ } , ..) , ..
4866+ } ) = node {
4867+ decl. clone ( ) . and_then ( |decl| {
4868+ Some ( ( decl, ident, false ) )
4869+ } )
4870+ } else {
4871+ None
4872+ }
4873+ }
4874+
48334875 /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
48344876 /// suggestion can be made, `None` otherwise.
48354877 pub fn get_fn_decl ( & self , blk_id : ast:: NodeId ) -> Option < ( hir:: FnDecl , bool ) > {
48364878 // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
48374879 // `while` before reaching it, as block tail returns are not available in them.
4838- if let Some ( fn_id) = self . tcx . hir ( ) . get_return_block ( blk_id) {
4839- let parent = self . tcx . hir ( ) . get ( fn_id) ;
4840-
4841- if let Node :: Item ( & hir:: Item {
4842- ident, node : hir:: ItemKind :: Fn ( ref decl, ..) , ..
4843- } ) = parent {
4844- decl. clone ( ) . and_then ( |decl| {
4845- // This is less than ideal, it will not suggest a return type span on any
4846- // method called `main`, regardless of whether it is actually the entry point,
4847- // but it will still present it as the reason for the expected type.
4848- Some ( ( decl, ident. name != Symbol :: intern ( "main" ) ) )
4849- } )
4850- } else if let Node :: TraitItem ( & hir:: TraitItem {
4851- node : hir:: TraitItemKind :: Method ( hir:: MethodSig {
4852- ref decl, ..
4853- } , ..) , ..
4854- } ) = parent {
4855- decl. clone ( ) . and_then ( |decl| {
4856- Some ( ( decl, true ) )
4857- } )
4858- } else if let Node :: ImplItem ( & hir:: ImplItem {
4859- node : hir:: ImplItemKind :: Method ( hir:: MethodSig {
4860- ref decl, ..
4861- } , ..) , ..
4862- } ) = parent {
4863- decl. clone ( ) . and_then ( |decl| {
4864- Some ( ( decl, false ) )
4865- } )
4866- } else {
4867- None
4868- }
4869- } else {
4870- None
4871- }
4880+ self . tcx . hir ( ) . get_return_block ( blk_id) . and_then ( |blk_id| {
4881+ let parent = self . tcx . hir ( ) . get ( blk_id) ;
4882+ self . get_node_fn_decl ( parent) . map ( |( fn_decl, _, is_main) | ( fn_decl, is_main) )
4883+ } )
48724884 }
48734885
48744886 /// On implicit return expressions with mismatched types, provide the following suggestions:
48754887 ///
48764888 /// - Point out the method's return type as the reason for the expected type
48774889 /// - Possible missing semicolon
48784890 /// - Possible missing return type if the return type is the default, and not `fn main()`
4879- pub fn suggest_mismatched_types_on_tail ( & self ,
4880- err : & mut DiagnosticBuilder < ' tcx > ,
4881- expression : & ' gcx hir:: Expr ,
4882- expected : Ty < ' tcx > ,
4883- found : Ty < ' tcx > ,
4884- cause_span : Span ,
4885- blk_id : ast:: NodeId ) {
4891+ pub fn suggest_mismatched_types_on_tail (
4892+ & self ,
4893+ err : & mut DiagnosticBuilder < ' tcx > ,
4894+ expression : & ' gcx hir:: Expr ,
4895+ expected : Ty < ' tcx > ,
4896+ found : Ty < ' tcx > ,
4897+ cause_span : Span ,
4898+ blk_id : ast:: NodeId ,
4899+ ) {
48864900 self . suggest_missing_semicolon ( err, expression, expected, cause_span) ;
48874901 if let Some ( ( fn_decl, can_suggest) ) = self . get_fn_decl ( blk_id) {
48884902 self . suggest_missing_return_type ( err, & fn_decl, expected, found, can_suggest) ;
0 commit comments