@@ -1416,57 +1416,117 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1416
1416
err : & mut Diagnostic ,
1417
1417
trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
1418
1418
) -> bool {
1419
- let span = obligation. cause . span ;
1419
+ let mut span = obligation. cause . span ;
1420
+ let mut trait_pred = trait_pred;
1421
+ let mut code = obligation. cause . code ( ) ;
1422
+ while let Some ( ( c, Some ( parent_trait_pred) ) ) = code. parent ( ) {
1423
+ // We want the root obligation, in order to detect properly handle
1424
+ // `for _ in &mut &mut vec![] {}`.
1425
+ code = c;
1426
+ trait_pred = parent_trait_pred;
1427
+ }
1428
+ while span. desugaring_kind ( ) . is_some ( ) {
1429
+ // Remove all the hir desugaring contexts while maintaining the macro contexts.
1430
+ span. remove_mark ( ) ;
1431
+ }
1432
+ let mut expr_finder = super :: FindExprBySpan :: new ( span) ;
1433
+ let Some ( hir:: Node :: Expr ( body) ) = self . tcx . hir ( ) . find ( obligation. cause . body_id ) else {
1434
+ return false ;
1435
+ } ;
1436
+ expr_finder. visit_expr ( & body) ;
1437
+ let mut maybe_suggest = |suggested_ty, count, suggestions| {
1438
+ // Remapping bound vars here
1439
+ let trait_pred_and_suggested_ty =
1440
+ trait_pred. map_bound ( |trait_pred| ( trait_pred, suggested_ty) ) ;
1441
+
1442
+ let new_obligation = self . mk_trait_obligation_with_new_self_ty (
1443
+ obligation. param_env ,
1444
+ trait_pred_and_suggested_ty,
1445
+ ) ;
1420
1446
1421
- let mut suggested = false ;
1422
- if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
1423
- let refs_number =
1424
- snippet. chars ( ) . filter ( |c| !c. is_whitespace ( ) ) . take_while ( |c| * c == '&' ) . count ( ) ;
1425
- if let Some ( '\'' ) = snippet. chars ( ) . filter ( |c| !c. is_whitespace ( ) ) . nth ( refs_number) {
1426
- // Do not suggest removal of borrow from type arguments.
1427
- return false ;
1447
+ if self . predicate_may_hold ( & new_obligation) {
1448
+ let msg = if count == 1 {
1449
+ "consider removing the leading `&`-reference" . to_string ( )
1450
+ } else {
1451
+ format ! ( "consider removing {count} leading `&`-references" )
1452
+ } ;
1453
+
1454
+ err. multipart_suggestion_verbose (
1455
+ & msg,
1456
+ suggestions,
1457
+ Applicability :: MachineApplicable ,
1458
+ ) ;
1459
+ true
1460
+ } else {
1461
+ false
1428
1462
}
1463
+ } ;
1429
1464
1430
- // Skipping binder here, remapping below
1431
- let mut suggested_ty = trait_pred. self_ty ( ) . skip_binder ( ) ;
1465
+ // Maybe suggest removal of borrows from types in type parameters, like in
1466
+ // `src/test/ui/not-panic/not-panic-safe.rs`.
1467
+ let mut count = 0 ;
1468
+ let mut suggestions = vec ! [ ] ;
1469
+ // Skipping binder here, remapping below
1470
+ let mut suggested_ty = trait_pred. self_ty ( ) . skip_binder ( ) ;
1471
+ if let Some ( mut hir_ty) = expr_finder. ty_result {
1472
+ while let hir:: TyKind :: Ref ( _, mut_ty) = & hir_ty. kind {
1473
+ count += 1 ;
1474
+ let span = hir_ty. span . until ( mut_ty. ty . span ) ;
1475
+ suggestions. push ( ( span, String :: new ( ) ) ) ;
1432
1476
1433
- for refs_remaining in 0 ..refs_number {
1434
1477
let ty:: Ref ( _, inner_ty, _) = suggested_ty. kind ( ) else {
1435
1478
break ;
1436
1479
} ;
1437
1480
suggested_ty = * inner_ty;
1438
1481
1439
- // Remapping bound vars here
1440
- let trait_pred_and_suggested_ty =
1441
- trait_pred. map_bound ( |trait_pred| ( trait_pred, suggested_ty) ) ;
1482
+ hir_ty = mut_ty. ty ;
1442
1483
1443
- let new_obligation = self . mk_trait_obligation_with_new_self_ty (
1444
- obligation. param_env ,
1445
- trait_pred_and_suggested_ty,
1446
- ) ;
1484
+ if maybe_suggest ( suggested_ty, count, suggestions. clone ( ) ) {
1485
+ return true ;
1486
+ }
1487
+ }
1488
+ }
1447
1489
1448
- if self . predicate_may_hold ( & new_obligation) {
1449
- let sp = self
1450
- . tcx
1451
- . sess
1452
- . source_map ( )
1453
- . span_take_while ( span, |c| c. is_whitespace ( ) || * c == '&' ) ;
1490
+ // Maybe suggest removal of borrows from expressions, like in `for i in &&&foo {}`.
1491
+ let Some ( mut expr) = expr_finder. result else { return false ; } ;
1492
+ let mut count = 0 ;
1493
+ let mut suggestions = vec ! [ ] ;
1494
+ // Skipping binder here, remapping below
1495
+ let mut suggested_ty = trait_pred. self_ty ( ) . skip_binder ( ) ;
1496
+ ' outer: loop {
1497
+ while let hir:: ExprKind :: AddrOf ( _, _, borrowed) = expr. kind {
1498
+ count += 1 ;
1499
+ let span = if expr. span . eq_ctxt ( borrowed. span ) {
1500
+ expr. span . until ( borrowed. span )
1501
+ } else {
1502
+ expr. span . with_hi ( expr. span . lo ( ) + BytePos ( 1 ) )
1503
+ } ;
1504
+ suggestions. push ( ( span, String :: new ( ) ) ) ;
1454
1505
1455
- let remove_refs = refs_remaining + 1 ;
1506
+ let ty:: Ref ( _, inner_ty, _) = suggested_ty. kind ( ) else {
1507
+ break ' outer;
1508
+ } ;
1509
+ suggested_ty = * inner_ty;
1456
1510
1457
- let msg = if remove_refs == 1 {
1458
- "consider removing the leading `&`-reference" . to_string ( )
1459
- } else {
1460
- format ! ( "consider removing {} leading `&`-references" , remove_refs)
1461
- } ;
1511
+ expr = borrowed;
1462
1512
1463
- err. span_suggestion_short ( sp, & msg, "" , Applicability :: MachineApplicable ) ;
1464
- suggested = true ;
1465
- break ;
1513
+ if maybe_suggest ( suggested_ty, count, suggestions. clone ( ) ) {
1514
+ return true ;
1466
1515
}
1467
1516
}
1517
+ if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
1518
+ && let hir:: def:: Res :: Local ( hir_id) = path. res
1519
+ && let Some ( hir:: Node :: Pat ( binding) ) = self . tcx . hir ( ) . find ( hir_id)
1520
+ && let Some ( hir:: Node :: Local ( local) ) = self . tcx . hir ( ) . find_parent ( binding. hir_id )
1521
+ && let None = local. ty
1522
+ && let Some ( binding_expr) = local. init
1523
+ {
1524
+ expr = binding_expr;
1525
+ } else {
1526
+ break ' outer;
1527
+ }
1468
1528
}
1469
- suggested
1529
+ false
1470
1530
}
1471
1531
1472
1532
fn suggest_remove_await ( & self , obligation : & PredicateObligation < ' tcx > , err : & mut Diagnostic ) {
0 commit comments