@@ -4796,16 +4796,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4796
4796
// `consider_hint_about_removing_semicolon` will point at the last expression
4797
4797
// if it were a relevant part of the error. This improves usability in editors
4798
4798
// 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 ) )
4801
4801
} else {
4802
- blk. span
4802
+ ( blk. span , None )
4803
4803
} ;
4804
4804
coerce. coerce_forced_unit ( self , & self . misc ( sp) , & mut |err| {
4805
4805
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
+ ) ;
4809
4813
}
4810
4814
} , false ) ;
4811
4815
}
@@ -4830,59 +4834,69 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4830
4834
ty
4831
4835
}
4832
4836
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
+
4833
4875
/// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
4834
4876
/// suggestion can be made, `None` otherwise.
4835
4877
pub fn get_fn_decl ( & self , blk_id : ast:: NodeId ) -> Option < ( hir:: FnDecl , bool ) > {
4836
4878
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
4837
4879
// `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
+ } )
4872
4884
}
4873
4885
4874
4886
/// On implicit return expressions with mismatched types, provide the following suggestions:
4875
4887
///
4876
4888
/// - Point out the method's return type as the reason for the expected type
4877
4889
/// - Possible missing semicolon
4878
4890
/// - 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
+ ) {
4886
4900
self . suggest_missing_semicolon ( err, expression, expected, cause_span) ;
4887
4901
if let Some ( ( fn_decl, can_suggest) ) = self . get_fn_decl ( blk_id) {
4888
4902
self . suggest_missing_return_type ( err, & fn_decl, expected, found, can_suggest) ;
0 commit comments