@@ -4229,8 +4229,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4229
4229
ty
4230
4230
}
4231
4231
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.
4234
4234
pub fn get_fn_decl ( & self , blk_id : ast:: NodeId ) -> Option < ( hir:: FnDecl , bool ) > {
4235
4235
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
4236
4236
// `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> {
4241
4241
name, node : hir:: ItemFn ( ref decl, ..) , ..
4242
4242
} ) = parent {
4243
4243
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" ) ) )
4247
4248
} )
4248
4249
} else if let Node :: NodeTraitItem ( & hir:: TraitItem {
4249
4250
node : hir:: TraitItemKind :: Method ( hir:: MethodSig {
4250
4251
ref decl, ..
4251
4252
} , ..) , ..
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
+ } , ..) , ..
4252
4261
} ) = parent {
4253
4262
decl. clone ( ) . and_then ( |decl| {
4254
4263
Some ( ( decl, false ) )
@@ -4275,11 +4284,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4275
4284
blk_id : ast:: NodeId ) {
4276
4285
self . suggest_missing_semicolon ( err, expression, expected, cause_span) ;
4277
4286
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) ;
4283
4289
}
4284
4290
}
4285
4291
@@ -4335,20 +4341,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4335
4341
fn suggest_missing_return_type ( & self ,
4336
4342
err : & mut DiagnosticBuilder < ' tcx > ,
4337
4343
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
4341
4348
// 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 ) => {
4346
4351
err. span_suggestion ( span,
4347
4352
"try adding a return type" ,
4348
- format ! ( "-> {} " , ty) ) ;
4349
- } else {
4353
+ format ! ( "-> {} " , found) ) ;
4354
+ }
4355
+ ( & hir:: FunctionRetTy :: DefaultReturn ( span) , false , true ) => {
4350
4356
err. span_label ( span, "possibly return type missing here?" ) ;
4351
4357
}
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
+ }
4352
4375
}
4353
4376
}
4354
4377
0 commit comments