@@ -530,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
530
530
531
531
// When encountering a type error on the value of a `break`, try to point at the reason for the
532
532
// expected type.
533
- fn annotate_loop_expected_due_to_inference (
533
+ pub fn annotate_loop_expected_due_to_inference (
534
534
& self ,
535
535
err : & mut Diagnostic ,
536
536
expr : & hir:: Expr < ' _ > ,
@@ -540,11 +540,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
540
540
return ;
541
541
} ;
542
542
let mut parent_id = self . tcx . hir ( ) . parent_id ( expr. hir_id ) ;
543
+ let mut parent;
543
544
loop {
544
545
// Climb the HIR tree to see if the current `Expr` is part of a `break;` statement.
545
- let Some ( hir:: Node :: Expr ( parent ) ) = self . tcx . hir ( ) . find ( parent_id) else {
546
+ let Some ( hir:: Node :: Expr ( p ) ) = self . tcx . hir ( ) . find ( parent_id) else {
546
547
break ;
547
548
} ;
549
+ parent = p;
548
550
parent_id = self . tcx . hir ( ) . parent_id ( parent. hir_id ) ;
549
551
let hir:: ExprKind :: Break ( destination, _) = parent. kind else {
550
552
continue ;
@@ -582,6 +584,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
582
584
span,
583
585
format ! ( "this loop is expected to be of type `{expected}`" ) ,
584
586
) ;
587
+ } else {
588
+ // Locate all other `break` statements within the same `loop` that might
589
+ // have affected inference.
590
+ struct FindBreaks < ' tcx > {
591
+ destination : hir:: Destination ,
592
+ uses : Vec < & ' tcx hir:: Expr < ' tcx > > ,
593
+ }
594
+ impl < ' tcx > Visitor < ' tcx > for FindBreaks < ' tcx > {
595
+ fn visit_expr ( & mut self , ex : & ' tcx hir:: Expr < ' tcx > ) {
596
+ if let hir:: ExprKind :: Break ( destination, _) = ex. kind
597
+ && self . destination . label == destination. label
598
+ {
599
+ self . uses . push ( ex) ;
600
+ }
601
+ hir:: intravisit:: walk_expr ( self , ex) ;
602
+ }
603
+ }
604
+ let mut expr_finder = FindBreaks { destination, uses : vec ! [ ] } ;
605
+ expr_finder. visit_expr ( parent) ;
606
+ for ex in expr_finder. uses {
607
+ let hir:: ExprKind :: Break ( _, val) = ex. kind else {
608
+ continue ;
609
+ } ;
610
+ let ty = match val {
611
+ Some ( val) => {
612
+ match self . typeck_results . borrow ( ) . expr_ty_adjusted_opt ( val) {
613
+ None => continue ,
614
+ Some ( ty) => ty,
615
+ }
616
+ }
617
+ None => self . tcx . types . unit ,
618
+ } ;
619
+ if self . can_eq ( self . param_env , ty, expected) {
620
+ err. span_label (
621
+ ex. span ,
622
+ format ! ( "expected because of this `break`" ) ,
623
+ ) ;
624
+ }
625
+ }
585
626
}
586
627
break ;
587
628
}
0 commit comments