@@ -1361,57 +1361,117 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
1361
1361
err : & mut Diagnostic ,
1362
1362
trait_pred : ty:: PolyTraitPredicate < ' tcx > ,
1363
1363
) -> bool {
1364
- let span = obligation. cause . span ;
1364
+ let mut span = obligation. cause . span ;
1365
+ let mut trait_pred = trait_pred;
1366
+ let mut code = obligation. cause . code ( ) ;
1367
+ while let Some ( ( c, Some ( parent_trait_pred) ) ) = code. parent ( ) {
1368
+ // We want the root obligation, in order to detect properly handle
1369
+ // `for _ in &mut &mut vec![] {}`.
1370
+ code = c;
1371
+ trait_pred = parent_trait_pred;
1372
+ }
1373
+ while span. desugaring_kind ( ) . is_some ( ) {
1374
+ // Remove all the hir desugaring contexts while maintaining the macro contexts.
1375
+ span. remove_mark ( ) ;
1376
+ }
1377
+ let mut expr_finder = super :: FindExprBySpan :: new ( span) ;
1378
+ let Some ( hir:: Node :: Expr ( body) ) = self . tcx . hir ( ) . find ( obligation. cause . body_id ) else {
1379
+ return false ;
1380
+ } ;
1381
+ expr_finder. visit_expr ( & body) ;
1382
+ let mut maybe_suggest = |suggested_ty, count, suggestions| {
1383
+ // Remapping bound vars here
1384
+ let trait_pred_and_suggested_ty =
1385
+ trait_pred. map_bound ( |trait_pred| ( trait_pred, suggested_ty) ) ;
1386
+
1387
+ let new_obligation = self . mk_trait_obligation_with_new_self_ty (
1388
+ obligation. param_env ,
1389
+ trait_pred_and_suggested_ty,
1390
+ ) ;
1365
1391
1366
- let mut suggested = false ;
1367
- if let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( span) {
1368
- let refs_number =
1369
- snippet. chars ( ) . filter ( |c| !c. is_whitespace ( ) ) . take_while ( |c| * c == '&' ) . count ( ) ;
1370
- if let Some ( '\'' ) = snippet. chars ( ) . filter ( |c| !c. is_whitespace ( ) ) . nth ( refs_number) {
1371
- // Do not suggest removal of borrow from type arguments.
1372
- return false ;
1392
+ if self . predicate_may_hold ( & new_obligation) {
1393
+ let msg = if count == 1 {
1394
+ "consider removing the leading `&`-reference" . to_string ( )
1395
+ } else {
1396
+ format ! ( "consider removing {count} leading `&`-references" )
1397
+ } ;
1398
+
1399
+ err. multipart_suggestion_verbose (
1400
+ & msg,
1401
+ suggestions,
1402
+ Applicability :: MachineApplicable ,
1403
+ ) ;
1404
+ true
1405
+ } else {
1406
+ false
1373
1407
}
1408
+ } ;
1374
1409
1375
- // Skipping binder here, remapping below
1376
- let mut suggested_ty = trait_pred. self_ty ( ) . skip_binder ( ) ;
1410
+ // Maybe suggest removal of borrows from types in type parameters, like in
1411
+ // `src/test/ui/not-panic/not-panic-safe.rs`.
1412
+ let mut count = 0 ;
1413
+ let mut suggestions = vec ! [ ] ;
1414
+ // Skipping binder here, remapping below
1415
+ let mut suggested_ty = trait_pred. self_ty ( ) . skip_binder ( ) ;
1416
+ if let Some ( mut hir_ty) = expr_finder. ty_result {
1417
+ while let hir:: TyKind :: Ref ( _, mut_ty) = & hir_ty. kind {
1418
+ count += 1 ;
1419
+ let span = hir_ty. span . until ( mut_ty. ty . span ) ;
1420
+ suggestions. push ( ( span, String :: new ( ) ) ) ;
1377
1421
1378
- for refs_remaining in 0 ..refs_number {
1379
1422
let ty:: Ref ( _, inner_ty, _) = suggested_ty. kind ( ) else {
1380
1423
break ;
1381
1424
} ;
1382
1425
suggested_ty = * inner_ty;
1383
1426
1384
- // Remapping bound vars here
1385
- let trait_pred_and_suggested_ty =
1386
- trait_pred. map_bound ( |trait_pred| ( trait_pred, suggested_ty) ) ;
1427
+ hir_ty = mut_ty. ty ;
1387
1428
1388
- let new_obligation = self . mk_trait_obligation_with_new_self_ty (
1389
- obligation. param_env ,
1390
- trait_pred_and_suggested_ty,
1391
- ) ;
1429
+ if maybe_suggest ( suggested_ty, count, suggestions. clone ( ) ) {
1430
+ return true ;
1431
+ }
1432
+ }
1433
+ }
1392
1434
1393
- if self . predicate_may_hold ( & new_obligation) {
1394
- let sp = self
1395
- . tcx
1396
- . sess
1397
- . source_map ( )
1398
- . span_take_while ( span, |c| c. is_whitespace ( ) || * c == '&' ) ;
1435
+ // Maybe suggest removal of borrows from expressions, like in `for i in &&&foo {}`.
1436
+ let Some ( mut expr) = expr_finder. result else { return false ; } ;
1437
+ let mut count = 0 ;
1438
+ let mut suggestions = vec ! [ ] ;
1439
+ // Skipping binder here, remapping below
1440
+ let mut suggested_ty = trait_pred. self_ty ( ) . skip_binder ( ) ;
1441
+ ' outer: loop {
1442
+ while let hir:: ExprKind :: AddrOf ( _, _, borrowed) = expr. kind {
1443
+ count += 1 ;
1444
+ let span = if expr. span . eq_ctxt ( borrowed. span ) {
1445
+ expr. span . until ( borrowed. span )
1446
+ } else {
1447
+ expr. span . with_hi ( expr. span . lo ( ) + BytePos ( 1 ) )
1448
+ } ;
1449
+ suggestions. push ( ( span, String :: new ( ) ) ) ;
1399
1450
1400
- let remove_refs = refs_remaining + 1 ;
1451
+ let ty:: Ref ( _, inner_ty, _) = suggested_ty. kind ( ) else {
1452
+ break ' outer;
1453
+ } ;
1454
+ suggested_ty = * inner_ty;
1401
1455
1402
- let msg = if remove_refs == 1 {
1403
- "consider removing the leading `&`-reference" . to_string ( )
1404
- } else {
1405
- format ! ( "consider removing {} leading `&`-references" , remove_refs)
1406
- } ;
1456
+ expr = borrowed;
1407
1457
1408
- err. span_suggestion_short ( sp, & msg, "" , Applicability :: MachineApplicable ) ;
1409
- suggested = true ;
1410
- break ;
1458
+ if maybe_suggest ( suggested_ty, count, suggestions. clone ( ) ) {
1459
+ return true ;
1411
1460
}
1412
1461
}
1462
+ if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = expr. kind
1463
+ && let hir:: def:: Res :: Local ( hir_id) = path. res
1464
+ && let Some ( hir:: Node :: Pat ( binding) ) = self . tcx . hir ( ) . find ( hir_id)
1465
+ && let Some ( hir:: Node :: Local ( local) ) = self . tcx . hir ( ) . find_parent ( binding. hir_id )
1466
+ && let None = local. ty
1467
+ && let Some ( binding_expr) = local. init
1468
+ {
1469
+ expr = binding_expr;
1470
+ } else {
1471
+ break ' outer;
1472
+ }
1413
1473
}
1414
- suggested
1474
+ false
1415
1475
}
1416
1476
1417
1477
fn suggest_remove_await ( & self , obligation : & PredicateObligation < ' tcx > , err : & mut Diagnostic ) {
0 commit comments