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