Skip to content

Commit 2024aa4

Browse files
committed
Make &-removal suggestion verbose
1 parent b22c152 commit 2024aa4

File tree

10 files changed

+113
-53
lines changed

10 files changed

+113
-53
lines changed

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

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,26 +1358,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
13581358
err: &mut Diagnostic,
13591359
trait_pred: ty::PolyTraitPredicate<'tcx>,
13601360
) -> bool {
1361-
let span = obligation.cause.span;
1362-
1361+
let mut span = obligation.cause.span;
1362+
while span.desugaring_kind().is_some() {
1363+
// Remove all the hir desugaring contexts while maintaining the macro contexts.
1364+
span.remove_mark();
1365+
}
13631366
let mut suggested = false;
1364-
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
1365-
let refs_number =
1366-
snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count();
1367-
if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) {
1368-
// Do not suggest removal of borrow from type arguments.
1369-
return false;
1370-
}
13711367

1372-
// Skipping binder here, remapping below
1373-
let mut suggested_ty = trait_pred.self_ty().skip_binder();
1368+
let mut expr_finder = super::FindExprBySpan { span, result: None };
1369+
let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else {
1370+
return false;
1371+
};
1372+
expr_finder.visit_expr(&body);
1373+
let mut count = 0;
1374+
let mut suggestions = vec![];
1375+
let Some(mut expr) = expr_finder.result else { return false; };
1376+
// Skipping binder here, remapping below
1377+
let mut suggested_ty = trait_pred.self_ty().skip_binder();
1378+
1379+
'outer: loop {
1380+
while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {
1381+
count += 1;
1382+
let span = if expr.span.eq_ctxt(borrowed.span) {
1383+
expr.span.until(borrowed.span)
1384+
} else {
1385+
expr.span.with_hi(expr.span.lo() + BytePos(1))
1386+
};
1387+
suggestions.push((span, String::new()));
13741388

1375-
for refs_remaining in 0..refs_number {
13761389
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
13771390
break;
13781391
};
13791392
suggested_ty = *inner_ty;
13801393

1394+
expr = borrowed;
1395+
13811396
// Remapping bound vars here
13821397
let trait_pred_and_suggested_ty =
13831398
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
@@ -1388,25 +1403,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
13881403
);
13891404

13901405
if self.predicate_may_hold(&new_obligation) {
1391-
let sp = self
1392-
.tcx
1393-
.sess
1394-
.source_map()
1395-
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
1396-
1397-
let remove_refs = refs_remaining + 1;
1398-
1399-
let msg = if remove_refs == 1 {
1406+
let msg = if count == 1 {
14001407
"consider removing the leading `&`-reference".to_string()
14011408
} else {
1402-
format!("consider removing {} leading `&`-references", remove_refs)
1409+
format!("consider removing {count} leading `&`-references")
14031410
};
14041411

1405-
err.span_suggestion_short(sp, &msg, "", Applicability::MachineApplicable);
1412+
err.multipart_suggestion_verbose(
1413+
&msg,
1414+
suggestions,
1415+
Applicability::MachineApplicable,
1416+
);
14061417
suggested = true;
1407-
break;
1418+
break 'outer;
14081419
}
14091420
}
1421+
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
1422+
&& let hir::def::Res::Local(hir_id) = path.res
1423+
&& let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id)
1424+
&& let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
1425+
&& let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
1426+
&& let None = local.ty
1427+
&& let Some(binding_expr) = local.init
1428+
{
1429+
expr = binding_expr;
1430+
} else {
1431+
break 'outer;
1432+
}
14101433
}
14111434
suggested
14121435
}

tests/ui/impl-trait/in-trait/issue-102140.stderr

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
22
--> $DIR/issue-102140.rs:23:22
33
|
44
LL | MyTrait::foo(&self)
5-
| ------------ -^^^^
6-
| | |
7-
| | the trait `MyTrait` is not implemented for `&dyn MyTrait`
8-
| | help: consider removing the leading `&`-reference
5+
| ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
6+
| |
97
| required by a bound introduced by this call
8+
|
9+
help: consider removing the leading `&`-reference
10+
|
11+
LL - MyTrait::foo(&self)
12+
LL + MyTrait::foo(self)
13+
|
1014

1115
error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
1216
--> $DIR/issue-102140.rs:23:9

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ error[E0277]: the type `&mut i32` may not be safely transferred across an unwind
22
--> $DIR/not-panic-safe.rs:8:14
33
|
44
LL | assert::<&mut i32>();
5-
| -^^^^^^^
6-
| |
7-
| `&mut i32` may not be safely transferred across an unwind boundary
8-
| help: consider removing the leading `&`-reference
5+
| ^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary
96
|
107
= help: the trait `UnwindSafe` is not implemented for `&mut i32`
118
= note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32`

tests/ui/suggestions/suggest-remove-refs-1.stderr

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ error[E0277]: `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
22
--> $DIR/suggest-remove-refs-1.rs:6:19
33
|
44
LL | for (i, _) in &v.iter().enumerate() {
5-
| -^^^^^^^^^^^^^^^^^^^^
6-
| |
7-
| `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
8-
| help: consider removing the leading `&`-reference
5+
| ^^^^^^^^^^^^^^^^^^^^^ `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
96
|
107
= help: the trait `Iterator` is not implemented for `&Enumerate<std::slice::Iter<'_, {integer}>>`
118
= note: required for `&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
9+
help: consider removing the leading `&`-reference
10+
|
11+
LL - for (i, _) in &v.iter().enumerate() {
12+
LL + for (i, _) in v.iter().enumerate() {
13+
|
1214

1315
error: aborting due to previous error
1416

tests/ui/suggestions/suggest-remove-refs-2.stderr

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ error[E0277]: `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterat
22
--> $DIR/suggest-remove-refs-2.rs:6:19
33
|
44
LL | for (i, _) in & & & & &v.iter().enumerate() {
5-
| ---------^^^^^^^^^^^^^^^^^^^^
6-
| |
7-
| `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
8-
| help: consider removing 5 leading `&`-references
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
96
|
107
= help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
118
= note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
9+
help: consider removing 5 leading `&`-references
10+
|
11+
LL - for (i, _) in & & & & &v.iter().enumerate() {
12+
LL + for (i, _) in v.iter().enumerate() {
13+
|
1214

1315
error: aborting due to previous error
1416

tests/ui/suggestions/suggest-remove-refs-3.stderr

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
error[E0277]: `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
22
--> $DIR/suggest-remove-refs-3.rs:6:19
33
|
4-
LL | for (i, _) in & & &
5-
| ____________________^
6-
| | ___________________|
7-
| ||
8-
LL | || & &v
9-
| ||___________- help: consider removing 5 leading `&`-references
10-
LL | | .iter()
11-
LL | | .enumerate() {
12-
| |_____________________^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
4+
LL | for (i, _) in & & &
5+
| ___________________^
6+
LL | | & &v
7+
LL | | .iter()
8+
LL | | .enumerate() {
9+
| |____________________^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
1310
|
1411
= help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
1512
= note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
13+
help: consider removing 5 leading `&`-references
14+
|
15+
LL - for (i, _) in & & &
16+
LL + for (i, _) in v
17+
|
1618

1719
error: aborting due to previous error
1820

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// run-rustfix
2+
fn main() {
3+
let foo = [1,2,3].iter();
4+
for _i in foo {} //~ ERROR E0277
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// run-rustfix
2+
fn main() {
3+
let foo = &[1,2,3].iter();
4+
for _i in &foo {} //~ ERROR E0277
5+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0277]: `&&std::slice::Iter<'_, {integer}>` is not an iterator
2+
--> $DIR/suggest-remove-refs-4.rs:4:15
3+
|
4+
LL | for _i in &foo {}
5+
| ^^^^ `&&std::slice::Iter<'_, {integer}>` is not an iterator
6+
|
7+
= help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>`
8+
= note: required for `&&std::slice::Iter<'_, {integer}>` to implement `IntoIterator`
9+
help: consider removing 2 leading `&`-references
10+
|
11+
LL ~ let foo = [1,2,3].iter();
12+
LL ~ for _i in foo {}
13+
|
14+
15+
error: aborting due to previous error
16+
17+
For more information about this error, try `rustc --explain E0277`.

tests/ui/typeck/issue-57404.stderr

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@ error[E0277]: `&mut ()` is not a tuple
22
--> $DIR/issue-57404.rs:6:41
33
|
44
LL | handlers.unwrap().as_mut().call_mut(&mut ());
5-
| -------- -^^^^^^
6-
| | |
7-
| | the trait `Tuple` is not implemented for `&mut ()`
8-
| | help: consider removing the leading `&`-reference
5+
| -------- ^^^^^^^ the trait `Tuple` is not implemented for `&mut ()`
6+
| |
97
| required by a bound introduced by this call
108
|
119
note: required by a bound in `call_mut`
1210
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
11+
help: consider removing the leading `&`-reference
12+
|
13+
LL - handlers.unwrap().as_mut().call_mut(&mut ());
14+
LL + handlers.unwrap().as_mut().call_mut(());
15+
|
1316

1417
error: aborting due to previous error
1518

0 commit comments

Comments
 (0)