@@ -8,7 +8,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
88use rustc_hir as hir;
99use rustc_hir:: def:: { CtorOf , DefKind } ;
1010use rustc_hir:: lang_items:: LangItem ;
11- use rustc_hir:: { ExprKind , ItemKind , Node } ;
11+ use rustc_hir:: { ExprKind , ItemKind , Node , StmtKind } ;
1212use rustc_infer:: infer;
1313use rustc_middle:: lint:: in_external_macro;
1414use rustc_middle:: ty:: { self , Binder , Ty } ;
@@ -55,7 +55,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5555 pointing_at_return_type =
5656 self . suggest_missing_return_type ( err, & fn_decl, expected, found, can_suggest) ;
5757 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+ ) ;
5961 }
6062 pointing_at_return_type
6163 }
@@ -472,22 +474,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
472474 }
473475 }
474476
475- pub ( in super :: super ) fn suggest_missing_return_expr (
477+ pub ( in super :: super ) fn suggest_missing_break_or_return_expr (
476478 & self ,
477479 err : & mut DiagnosticBuilder < ' _ > ,
478480 expr : & ' tcx hir:: Expr < ' tcx > ,
479481 fn_decl : & hir:: FnDecl < ' _ > ,
480482 expected : Ty < ' tcx > ,
481483 found : Ty < ' tcx > ,
482484 id : hir:: HirId ,
485+ fn_id : hir:: HirId ,
483486 ) {
484487 if !expected. is_unit ( ) {
485488 return ;
486489 }
487490 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+
488506 if let hir:: FnRetTy :: Return ( ty) = fn_decl. output {
489507 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 ) ;
491509 let ty = self . tcx . erase_late_bound_regions ( Binder :: bind_with_vars ( ty, bound_vars) ) ;
492510 let ty = self . normalize_associated_types_in ( expr. span , ty) ;
493511 if self . can_coerce ( found, ty) {
@@ -514,4 +532,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
514532 self . tcx . sess . parse_sess . expr_parentheses_needed ( err, * sp, None ) ;
515533 }
516534 }
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+ }
517587}
0 commit comments