@@ -4187,8 +4187,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
41874187 ty
41884188 }
41894189
4190- /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
4191- /// `fn main` if it is a method , `None` otherwise.
4190+ /// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
4191+ /// suggetion can be made , `None` otherwise.
41924192 pub fn get_fn_decl ( & self , blk_id : ast:: NodeId ) -> Option < ( hir:: FnDecl , bool ) > {
41934193 // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
41944194 // `while` before reaching it, as block tail returns are not available in them.
@@ -4199,14 +4199,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
41994199 name, node : hir:: ItemFn ( ref decl, ..) , ..
42004200 } ) = parent {
42014201 decl. clone ( ) . and_then ( |decl| {
4202- // This is less than ideal, it will not present the return type span on any
4203- // method called `main`, regardless of whether it is actually the entry point.
4204- Some ( ( decl, name == Symbol :: intern ( "main" ) ) )
4202+ // This is less than ideal, it will not suggest a return type span on any
4203+ // method called `main`, regardless of whether it is actually the entry point,
4204+ // but it will still present it as the reason for the expected type.
4205+ Some ( ( decl, name != Symbol :: intern ( "main" ) ) )
42054206 } )
42064207 } else if let Node :: NodeTraitItem ( & hir:: TraitItem {
42074208 node : hir:: TraitItemKind :: Method ( hir:: MethodSig {
42084209 ref decl, ..
42094210 } , ..) , ..
4211+ } ) = parent {
4212+ decl. clone ( ) . and_then ( |decl| {
4213+ Some ( ( decl, true ) )
4214+ } )
4215+ } else if let Node :: NodeImplItem ( & hir:: ImplItem {
4216+ node : hir:: ImplItemKind :: Method ( hir:: MethodSig {
4217+ ref decl, ..
4218+ } , ..) , ..
42104219 } ) = parent {
42114220 decl. clone ( ) . and_then ( |decl| {
42124221 Some ( ( decl, false ) )
@@ -4233,11 +4242,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42334242 blk_id : ast:: NodeId ) {
42344243 self . suggest_missing_semicolon ( err, expression, expected, cause_span) ;
42354244
4236- if let Some ( ( fn_decl, is_main) ) = self . get_fn_decl ( blk_id) {
4237- // `fn main()` must return `()`, do not suggest changing return type
4238- if !is_main {
4239- self . suggest_missing_return_type ( err, & fn_decl, found) ;
4240- }
4245+ if let Some ( ( fn_decl, can_suggest) ) = self . get_fn_decl ( blk_id) {
4246+ self . suggest_missing_return_type ( err, & fn_decl, expected, found, can_suggest) ;
42414247 }
42424248 }
42434249
@@ -4293,20 +4299,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42934299 fn suggest_missing_return_type ( & self ,
42944300 err : & mut DiagnosticBuilder < ' tcx > ,
42954301 fn_decl : & hir:: FnDecl ,
4296- ty : Ty < ' tcx > ) {
4302+ expected : Ty < ' tcx > ,
4303+ found : Ty < ' tcx > ,
4304+ can_suggest : bool ) {
42974305
4298- // Only recommend changing the return type for methods that
4306+ // Only suggest changing the return type for methods that
42994307 // haven't set a return type at all (and aren't `fn main()` or an impl).
4300- if let & hir:: FnDecl {
4301- output : hir:: FunctionRetTy :: DefaultReturn ( span) , ..
4302- } = fn_decl {
4303- if ty. is_suggestable ( ) {
4308+ match ( & fn_decl. output , found. is_suggestable ( ) , can_suggest) {
4309+ ( & hir:: FunctionRetTy :: DefaultReturn ( span) , true , true ) => {
43044310 err. span_suggestion ( span,
43054311 "try adding a return type" ,
4306- format ! ( "-> {} " , ty) ) ;
4307- } else {
4312+ format ! ( "-> {} " , found) ) ;
4313+ }
4314+ ( & hir:: FunctionRetTy :: DefaultReturn ( span) , false , true ) => {
43084315 err. span_label ( span, "possibly return type missing here?" ) ;
43094316 }
4317+ ( & hir:: FunctionRetTy :: DefaultReturn ( span) , _, _) => {
4318+ // `fn main()` must return `()`, do not suggest changing return type
4319+ err. span_label ( span, "expected `()` because of default return type" ) ;
4320+ }
4321+ ( & hir:: FunctionRetTy :: Return ( ref ty) , _, _) => {
4322+ // Only point to return type if the expected type is the return type, as if they
4323+ // are not, the expectation must have been caused by something else.
4324+ err. span_label ( ty. span ,
4325+ format ! ( "expected `{}` because of return type" , expected) ) ;
4326+ }
43104327 }
43114328 }
43124329
0 commit comments