Skip to content

Commit ce83be4

Browse files
committed
Account for type params
1 parent 2024aa4 commit ce83be4

File tree

4 files changed

+81
-38
lines changed

4 files changed

+81
-38
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,19 +1363,70 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
13631363
// Remove all the hir desugaring contexts while maintaining the macro contexts.
13641364
span.remove_mark();
13651365
}
1366-
let mut suggested = false;
1367-
1368-
let mut expr_finder = super::FindExprBySpan { span, result: None };
1366+
let mut expr_finder = super::FindExprBySpan::new(span);
13691367
let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else {
13701368
return false;
13711369
};
13721370
expr_finder.visit_expr(&body);
1371+
let mut maybe_suggest = |suggested_ty, count, suggestions| {
1372+
// Remapping bound vars here
1373+
let trait_pred_and_suggested_ty =
1374+
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
1375+
1376+
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
1377+
obligation.param_env,
1378+
trait_pred_and_suggested_ty,
1379+
);
1380+
1381+
if self.predicate_may_hold(&new_obligation) {
1382+
let msg = if count == 1 {
1383+
"consider removing the leading `&`-reference".to_string()
1384+
} else {
1385+
format!("consider removing {count} leading `&`-references")
1386+
};
1387+
1388+
err.multipart_suggestion_verbose(
1389+
&msg,
1390+
suggestions,
1391+
Applicability::MachineApplicable,
1392+
);
1393+
true
1394+
} else {
1395+
false
1396+
}
1397+
};
1398+
1399+
// Maybe suggest removal of borrows from types in type parameters, like in
1400+
// `src/test/ui/not-panic/not-panic-safe.rs`.
13731401
let mut count = 0;
13741402
let mut suggestions = vec![];
1375-
let Some(mut expr) = expr_finder.result else { return false; };
13761403
// Skipping binder here, remapping below
13771404
let mut suggested_ty = trait_pred.self_ty().skip_binder();
1405+
if let Some(mut hir_ty) = expr_finder.ty_result {
1406+
while let hir::TyKind::Ref(_, mut_ty) = &hir_ty.kind {
1407+
count += 1;
1408+
let span = hir_ty.span.until(mut_ty.ty.span);
1409+
suggestions.push((span, String::new()));
1410+
1411+
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
1412+
break;
1413+
};
1414+
suggested_ty = *inner_ty;
1415+
1416+
hir_ty = mut_ty.ty;
1417+
1418+
if maybe_suggest(suggested_ty, count, suggestions.clone()) {
1419+
return true;
1420+
}
1421+
}
1422+
}
13781423

1424+
// Maybe suggest removal of borrows from expressions, like in `for i in &&&foo {}`.
1425+
let Some(mut expr) = expr_finder.result else { return false; };
1426+
let mut count = 0;
1427+
let mut suggestions = vec![];
1428+
// Skipping binder here, remapping below
1429+
let mut suggested_ty = trait_pred.self_ty().skip_binder();
13791430
'outer: loop {
13801431
while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {
13811432
count += 1;
@@ -1387,35 +1438,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
13871438
suggestions.push((span, String::new()));
13881439

13891440
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
1390-
break;
1441+
break 'outer;
13911442
};
13921443
suggested_ty = *inner_ty;
13931444

13941445
expr = borrowed;
13951446

1396-
// Remapping bound vars here
1397-
let trait_pred_and_suggested_ty =
1398-
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
1399-
1400-
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
1401-
obligation.param_env,
1402-
trait_pred_and_suggested_ty,
1403-
);
1404-
1405-
if self.predicate_may_hold(&new_obligation) {
1406-
let msg = if count == 1 {
1407-
"consider removing the leading `&`-reference".to_string()
1408-
} else {
1409-
format!("consider removing {count} leading `&`-references")
1410-
};
1411-
1412-
err.multipart_suggestion_verbose(
1413-
&msg,
1414-
suggestions,
1415-
Applicability::MachineApplicable,
1416-
);
1417-
suggested = true;
1418-
break 'outer;
1447+
if maybe_suggest(suggested_ty, count, suggestions.clone()) {
1448+
return true;
14191449
}
14201450
}
14211451
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
@@ -1431,7 +1461,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
14311461
break 'outer;
14321462
}
14331463
}
1434-
suggested
1464+
false
14351465
}
14361466

14371467
fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) {

tests/ui/kindck/kindck-copy.stderr

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,33 @@ error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied
44
LL | assert_copy::<&'static mut isize>();
55
| ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize`
66
|
7-
= help: the trait `Copy` is implemented for `isize`
87
note: required by a bound in `assert_copy`
98
--> $DIR/kindck-copy.rs:5:18
109
|
1110
LL | fn assert_copy<T:Copy>() { }
1211
| ^^^^ required by this bound in `assert_copy`
12+
help: consider removing the leading `&`-reference
13+
|
14+
LL - assert_copy::<&'static mut isize>();
15+
LL + assert_copy::<isize>();
16+
|
1317

1418
error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied
1519
--> $DIR/kindck-copy.rs:28:19
1620
|
1721
LL | assert_copy::<&'a mut isize>();
1822
| ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize`
1923
|
20-
= help: the trait `Copy` is implemented for `isize`
2124
note: required by a bound in `assert_copy`
2225
--> $DIR/kindck-copy.rs:5:18
2326
|
2427
LL | fn assert_copy<T:Copy>() { }
2528
| ^^^^ required by this bound in `assert_copy`
29+
help: consider removing the leading `&`-reference
30+
|
31+
LL - assert_copy::<&'a mut isize>();
32+
LL + assert_copy::<isize>();
33+
|
2634

2735
error[E0277]: the trait bound `Box<isize>: Copy` is not satisfied
2836
--> $DIR/kindck-copy.rs:31:19

tests/ui/not-panic/not-panic-safe.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ use std::panic::UnwindSafe;
55
fn assert<T: UnwindSafe + ?Sized>() {}
66

77
fn main() {
8-
assert::<&mut i32>();
9-
//~^ ERROR the type `&mut i32` may not be safely transferred across an unwind boundary
8+
assert::<&mut &mut &i32>();
9+
//~^ ERROR the type `&mut &mut &i32` may not be safely transferred across an unwind boundary
1010
}

tests/ui/not-panic/not-panic-safe.stderr

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1-
error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary
1+
error[E0277]: the type `&mut &mut &i32` may not be safely transferred across an unwind boundary
22
--> $DIR/not-panic-safe.rs:8:14
33
|
4-
LL | assert::<&mut i32>();
5-
| ^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary
4+
LL | assert::<&mut &mut &i32>();
5+
| ^^^^^^^^^^^^^^ `&mut &mut &i32` may not be safely transferred across an unwind boundary
66
|
7-
= help: the trait `UnwindSafe` is not implemented for `&mut i32`
8-
= note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32`
7+
= help: the trait `UnwindSafe` is not implemented for `&mut &mut &i32`
8+
= note: `UnwindSafe` is implemented for `&&mut &i32`, but not for `&mut &mut &i32`
99
note: required by a bound in `assert`
1010
--> $DIR/not-panic-safe.rs:5:14
1111
|
1212
LL | fn assert<T: UnwindSafe + ?Sized>() {}
1313
| ^^^^^^^^^^ required by this bound in `assert`
14+
help: consider removing 2 leading `&`-references
15+
|
16+
LL - assert::<&mut &mut &i32>();
17+
LL + assert::<&i32>();
18+
|
1419

1520
error: aborting due to previous error
1621

0 commit comments

Comments
 (0)