@@ -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:: { ExprKind , ItemKind , Node , 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,38 @@ 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
+ if self . in_loop ( id) {
493
+ if self . in_local_statement ( id) {
494
+ err. multipart_suggestion (
495
+ "you might have meant to break the loop with this value" ,
496
+ vec ! [
497
+ ( expr. span. shrink_to_lo( ) , "break " . to_string( ) ) ,
498
+ ( expr. span. shrink_to_hi( ) , ";" . to_string( ) ) ,
499
+ ] ,
500
+ Applicability :: MaybeIncorrect ,
501
+ ) ;
502
+ return ;
503
+ }
504
+ }
505
+
488
506
if let hir:: FnRetTy :: Return ( ty) = fn_decl. output {
489
507
let ty = <dyn AstConv < ' _ > >:: ast_ty_to_ty ( self , ty) ;
490
- let bound_vars = self . tcx . late_bound_vars ( id ) ;
508
+ let bound_vars = self . tcx . late_bound_vars ( fn_id ) ;
491
509
let ty = self . tcx . erase_late_bound_regions ( Binder :: bind_with_vars ( ty, bound_vars) ) ;
492
510
let ty = self . normalize_associated_types_in ( expr. span , ty) ;
493
511
if self . can_coerce ( found, ty) {
@@ -514,4 +532,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
514
532
self . tcx . sess . parse_sess . expr_parentheses_needed ( err, * sp, None ) ;
515
533
}
516
534
}
535
+
536
+ fn in_loop ( & self , id : hir:: HirId ) -> bool {
537
+ if self . is_loop ( id) {
538
+ return true ;
539
+ }
540
+
541
+ for ( parent_id, _) in self . tcx . hir ( ) . parent_iter ( id) {
542
+ if self . is_loop ( parent_id) {
543
+ return true ;
544
+ }
545
+ }
546
+
547
+ false
548
+ }
549
+
550
+ fn is_loop ( & self , id : hir:: HirId ) -> bool {
551
+ let node = self . tcx . hir ( ) . get ( id) ;
552
+
553
+ if let Node :: Expr ( expr) = node {
554
+ if let ExprKind :: Loop ( ..) = expr. kind {
555
+ return true ;
556
+ }
557
+ }
558
+
559
+ false
560
+ }
561
+
562
+ fn in_local_statement ( & self , id : hir:: HirId ) -> bool {
563
+ if self . is_local_statement ( id) {
564
+ return true ;
565
+ }
566
+
567
+ for ( parent_id, _) in self . tcx . hir ( ) . parent_iter ( id) {
568
+ if self . is_local_statement ( parent_id) {
569
+ return true ;
570
+ }
571
+ }
572
+
573
+ false
574
+ }
575
+
576
+ fn is_local_statement ( & self , id : hir:: HirId ) -> bool {
577
+ let node = self . tcx . hir ( ) . get ( id) ;
578
+
579
+ if let Node :: Stmt ( stmt) = node {
580
+ if let StmtKind :: Local ( ..) = stmt. kind {
581
+ return true ;
582
+ }
583
+ }
584
+
585
+ false
586
+ }
517
587
}
0 commit comments