@@ -8,7 +8,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
8
8
use rustc_hir as hir;
9
9
use rustc_hir:: def:: { CtorOf , DefKind } ;
10
10
use rustc_hir:: lang_items:: LangItem ;
11
- use rustc_hir:: { ExprKind , ItemKind , Node } ;
11
+ use rustc_hir:: { Expr , ExprKind , ItemKind , Node , Stmt , StmtKind } ;
12
12
use rustc_infer:: infer;
13
13
use rustc_middle:: lint:: in_external_macro;
14
14
use rustc_middle:: ty:: { self , Binder , Ty } ;
@@ -55,7 +55,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
55
55
pointing_at_return_type =
56
56
self . suggest_missing_return_type ( err, & fn_decl, expected, found, can_suggest) ;
57
57
let fn_id = self . tcx . hir ( ) . get_return_block ( blk_id) . unwrap ( ) ;
58
- self . suggest_missing_return_expr ( err, expr, & fn_decl, expected, found, fn_id) ;
58
+ self . suggest_missing_break_or_return_expr (
59
+ err, expr, & fn_decl, expected, found, blk_id, fn_id,
60
+ ) ;
59
61
}
60
62
pointing_at_return_type
61
63
}
@@ -472,22 +474,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
472
474
}
473
475
}
474
476
475
- pub ( in super :: super ) fn suggest_missing_return_expr (
477
+ pub ( in super :: super ) fn suggest_missing_break_or_return_expr (
476
478
& self ,
477
479
err : & mut DiagnosticBuilder < ' _ > ,
478
480
expr : & ' tcx hir:: Expr < ' tcx > ,
479
481
fn_decl : & hir:: FnDecl < ' _ > ,
480
482
expected : Ty < ' tcx > ,
481
483
found : Ty < ' tcx > ,
482
484
id : hir:: HirId ,
485
+ fn_id : hir:: HirId ,
483
486
) {
484
487
if !expected. is_unit ( ) {
485
488
return ;
486
489
}
487
490
let found = self . resolve_vars_with_obligations ( found) ;
491
+
492
+ let in_loop = self . is_loop ( id)
493
+ || self . tcx . hir ( ) . parent_iter ( id) . any ( |( parent_id, _) | self . is_loop ( parent_id) ) ;
494
+
495
+ let in_local_statement = self . is_local_statement ( id)
496
+ || self
497
+ . tcx
498
+ . hir ( )
499
+ . parent_iter ( id)
500
+ . any ( |( parent_id, _) | self . is_local_statement ( parent_id) ) ;
501
+
502
+ if in_loop && in_local_statement {
503
+ err. multipart_suggestion (
504
+ "you might have meant to break the loop with this value" ,
505
+ vec ! [
506
+ ( expr. span. shrink_to_lo( ) , "break " . to_string( ) ) ,
507
+ ( expr. span. shrink_to_hi( ) , ";" . to_string( ) ) ,
508
+ ] ,
509
+ Applicability :: MaybeIncorrect ,
510
+ ) ;
511
+ return ;
512
+ }
513
+
488
514
if let hir:: FnRetTy :: Return ( ty) = fn_decl. output {
489
515
let ty = <dyn AstConv < ' _ > >:: ast_ty_to_ty ( self , ty) ;
490
- let bound_vars = self . tcx . late_bound_vars ( id ) ;
516
+ let bound_vars = self . tcx . late_bound_vars ( fn_id ) ;
491
517
let ty = self . tcx . erase_late_bound_regions ( Binder :: bind_with_vars ( ty, bound_vars) ) ;
492
518
let ty = self . normalize_associated_types_in ( expr. span , ty) ;
493
519
if self . can_coerce ( found, ty) {
@@ -514,4 +540,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
514
540
self . tcx . sess . parse_sess . expr_parentheses_needed ( err, * sp, None ) ;
515
541
}
516
542
}
543
+
544
+ fn is_loop ( & self , id : hir:: HirId ) -> bool {
545
+ let node = self . tcx . hir ( ) . get ( id) ;
546
+ matches ! ( node, Node :: Expr ( Expr { kind: ExprKind :: Loop ( ..) , .. } ) )
547
+ }
548
+
549
+ fn is_local_statement ( & self , id : hir:: HirId ) -> bool {
550
+ let node = self . tcx . hir ( ) . get ( id) ;
551
+ matches ! ( node, Node :: Stmt ( Stmt { kind: StmtKind :: Local ( ..) , .. } ) )
552
+ }
517
553
}
0 commit comments