@@ -4229,8 +4229,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42294229 ty
42304230 }
42314231
4232- /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
4233- /// `fn main` if it is a method , `None` otherwise.
4232+ /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
4233+ /// suggetion can be made , `None` otherwise.
42344234 pub fn get_fn_decl ( & self , blk_id : ast:: NodeId ) -> Option < ( hir:: FnDecl , bool ) > {
42354235 // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
42364236 // `while` before reaching it, as block tail returns are not available in them.
@@ -4241,14 +4241,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42414241 name, node : hir:: ItemFn ( ref decl, ..) , ..
42424242 } ) = parent {
42434243 decl. clone ( ) . and_then ( |decl| {
4244- // This is less than ideal, it will not present the return type span on any
4245- // method called `main`, regardless of whether it is actually the entry point.
4246- Some ( ( decl, name == Symbol :: intern ( "main" ) ) )
4244+ // This is less than ideal, it will not suggest a return type span on any
4245+ // method called `main`, regardless of whether it is actually the entry point,
4246+ // but it will still present it as the reason for the expected type.
4247+ Some ( ( decl, name != Symbol :: intern ( "main" ) ) )
42474248 } )
42484249 } else if let Node :: NodeTraitItem ( & hir:: TraitItem {
42494250 node : hir:: TraitItemKind :: Method ( hir:: MethodSig {
42504251 ref decl, ..
42514252 } , ..) , ..
4253+ } ) = parent {
4254+ decl. clone ( ) . and_then ( |decl| {
4255+ Some ( ( decl, true ) )
4256+ } )
4257+ } else if let Node :: NodeImplItem ( & hir:: ImplItem {
4258+ node : hir:: ImplItemKind :: Method ( hir:: MethodSig {
4259+ ref decl, ..
4260+ } , ..) , ..
42524261 } ) = parent {
42534262 decl. clone ( ) . and_then ( |decl| {
42544263 Some ( ( decl, false ) )
@@ -4275,11 +4284,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42754284 blk_id : ast:: NodeId ) {
42764285 self . suggest_missing_semicolon ( err, expression, expected, cause_span) ;
42774286
4278- if let Some ( ( fn_decl, is_main) ) = self . get_fn_decl ( blk_id) {
4279- // `fn main()` must return `()`, do not suggest changing return type
4280- if !is_main {
4281- self . suggest_missing_return_type ( err, & fn_decl, found) ;
4282- }
4287+ if let Some ( ( fn_decl, can_suggest) ) = self . get_fn_decl ( blk_id) {
4288+ self . suggest_missing_return_type ( err, & fn_decl, expected, found, can_suggest) ;
42834289 }
42844290 }
42854291
@@ -4335,20 +4341,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
43354341 fn suggest_missing_return_type ( & self ,
43364342 err : & mut DiagnosticBuilder < ' tcx > ,
43374343 fn_decl : & hir:: FnDecl ,
4338- ty : Ty < ' tcx > ) {
4339-
4340- // Only recommend changing the return type for methods that
4344+ expected : Ty < ' tcx > ,
4345+ found : Ty < ' tcx > ,
4346+ can_suggest : bool ) {
4347+ // Only suggest changing the return type for methods that
43414348 // haven't set a return type at all (and aren't `fn main()` or an impl).
4342- if let & hir:: FnDecl {
4343- output : hir:: FunctionRetTy :: DefaultReturn ( span) , ..
4344- } = fn_decl {
4345- if ty. is_suggestable ( ) {
4349+ match ( & fn_decl. output , found. is_suggestable ( ) , can_suggest) {
4350+ ( & hir:: FunctionRetTy :: DefaultReturn ( span) , true , true ) => {
43464351 err. span_suggestion ( span,
43474352 "try adding a return type" ,
4348- format ! ( "-> {} " , ty) ) ;
4349- } else {
4353+ format ! ( "-> {} " , found) ) ;
4354+ }
4355+ ( & hir:: FunctionRetTy :: DefaultReturn ( span) , false , true ) => {
43504356 err. span_label ( span, "possibly return type missing here?" ) ;
43514357 }
4358+ ( & hir:: FunctionRetTy :: DefaultReturn ( span) , _, _) => {
4359+ // `fn main()` must return `()`, do not suggest changing return type
4360+ err. span_label ( span, "expected `()` because of default return type" ) ;
4361+ }
4362+ ( & hir:: FunctionRetTy :: Return ( ref ty) , _, _) => {
4363+ // Only point to return type if the expected type is the return type, as if they
4364+ // are not, the expectation must have been caused by something else.
4365+ debug ! ( "suggest_missing_return_type: return type {:?} node {:?}" , ty, ty. node) ;
4366+ let sp = ty. span ;
4367+ let ty = AstConv :: ast_ty_to_ty ( self , ty) ;
4368+ debug ! ( "suggest_missing_return_type: return type sty {:?}" , ty. sty) ;
4369+ debug ! ( "suggest_missing_return_type: expected type sty {:?}" , ty. sty) ;
4370+ if ty. sty == expected. sty {
4371+ err. span_label ( sp, format ! ( "expected `{}` because of return type" ,
4372+ expected) ) ;
4373+ }
4374+ }
43524375 }
43534376 }
43544377
0 commit comments