@@ -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