Make &-removal suggestion verbose

This commit is contained in:
Esteban Küber 2023-01-01 18:43:47 -08:00
parent b22c152958
commit 2024aa48b4
10 changed files with 113 additions and 53 deletions

View File

@ -1358,26 +1358,41 @@ fn suggest_remove_reference(
err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
let span = obligation.cause.span;
let mut span = obligation.cause.span;
while span.desugaring_kind().is_some() {
// Remove all the hir desugaring contexts while maintaining the macro contexts.
span.remove_mark();
}
let mut suggested = false;
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
let refs_number =
snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count();
if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) {
// Do not suggest removal of borrow from type arguments.
return false;
}
// Skipping binder here, remapping below
let mut suggested_ty = trait_pred.self_ty().skip_binder();
let mut expr_finder = super::FindExprBySpan { span, result: None };
let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else {
return false;
};
expr_finder.visit_expr(&body);
let mut count = 0;
let mut suggestions = vec![];
let Some(mut expr) = expr_finder.result else { return false; };
// Skipping binder here, remapping below
let mut suggested_ty = trait_pred.self_ty().skip_binder();
'outer: loop {
while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {
count += 1;
let span = if expr.span.eq_ctxt(borrowed.span) {
expr.span.until(borrowed.span)
} else {
expr.span.with_hi(expr.span.lo() + BytePos(1))
};
suggestions.push((span, String::new()));
for refs_remaining in 0..refs_number {
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
break;
};
suggested_ty = *inner_ty;
expr = borrowed;
// Remapping bound vars here
let trait_pred_and_suggested_ty =
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
@ -1388,25 +1403,33 @@ fn suggest_remove_reference(
);
if self.predicate_may_hold(&new_obligation) {
let sp = self
.tcx
.sess
.source_map()
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
let remove_refs = refs_remaining + 1;
let msg = if remove_refs == 1 {
let msg = if count == 1 {
"consider removing the leading `&`-reference".to_string()
} else {
format!("consider removing {} leading `&`-references", remove_refs)
format!("consider removing {count} leading `&`-references")
};
err.span_suggestion_short(sp, &msg, "", Applicability::MachineApplicable);
err.multipart_suggestion_verbose(
&msg,
suggestions,
Applicability::MachineApplicable,
);
suggested = true;
break;
break 'outer;
}
}
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::def::Res::Local(hir_id) = path.res
&& let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id)
&& let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id)
&& let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id)
&& let None = local.ty
&& let Some(binding_expr) = local.init
{
expr = binding_expr;
} else {
break 'outer;
}
}
suggested
}

View File

@ -2,11 +2,15 @@ error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
--> $DIR/issue-102140.rs:23:22
|
LL | MyTrait::foo(&self)
| ------------ -^^^^
| | |
| | the trait `MyTrait` is not implemented for `&dyn MyTrait`
| | help: consider removing the leading `&`-reference
| ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
| |
| required by a bound introduced by this call
|
help: consider removing the leading `&`-reference
|
LL - MyTrait::foo(&self)
LL + MyTrait::foo(self)
|
error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
--> $DIR/issue-102140.rs:23:9

View File

@ -2,10 +2,7 @@ error[E0277]: the type `&mut i32` may not be safely transferred across an unwind
--> $DIR/not-panic-safe.rs:8:14
|
LL | assert::<&mut i32>();
| -^^^^^^^
| |
| `&mut i32` may not be safely transferred across an unwind boundary
| help: consider removing the leading `&`-reference
| ^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary
|
= help: the trait `UnwindSafe` is not implemented for `&mut i32`
= note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32`

View File

@ -2,13 +2,15 @@ error[E0277]: `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
--> $DIR/suggest-remove-refs-1.rs:6:19
|
LL | for (i, _) in &v.iter().enumerate() {
| -^^^^^^^^^^^^^^^^^^^^
| |
| `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
| help: consider removing the leading `&`-reference
| ^^^^^^^^^^^^^^^^^^^^^ `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&Enumerate<std::slice::Iter<'_, {integer}>>`
= note: required for `&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
help: consider removing the leading `&`-reference
|
LL - for (i, _) in &v.iter().enumerate() {
LL + for (i, _) in v.iter().enumerate() {
|
error: aborting due to previous error

View File

@ -2,13 +2,15 @@ error[E0277]: `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterat
--> $DIR/suggest-remove-refs-2.rs:6:19
|
LL | for (i, _) in & & & & &v.iter().enumerate() {
| ---------^^^^^^^^^^^^^^^^^^^^
| |
| `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
| help: consider removing 5 leading `&`-references
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
= note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
help: consider removing 5 leading `&`-references
|
LL - for (i, _) in & & & & &v.iter().enumerate() {
LL + for (i, _) in v.iter().enumerate() {
|
error: aborting due to previous error

View File

@ -1,18 +1,20 @@
error[E0277]: `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
--> $DIR/suggest-remove-refs-3.rs:6:19
|
LL | for (i, _) in & & &
| ____________________^
| | ___________________|
| ||
LL | || & &v
| ||___________- help: consider removing 5 leading `&`-references
LL | | .iter()
LL | | .enumerate() {
| |_____________________^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
LL | for (i, _) in & & &
| ___________________^
LL | | & &v
LL | | .iter()
LL | | .enumerate() {
| |____________________^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
= note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
help: consider removing 5 leading `&`-references
|
LL - for (i, _) in & & &
LL + for (i, _) in v
|
error: aborting due to previous error

View File

@ -0,0 +1,5 @@
// run-rustfix
fn main() {
let foo = [1,2,3].iter();
for _i in foo {} //~ ERROR E0277
}

View File

@ -0,0 +1,5 @@
// run-rustfix
fn main() {
let foo = &[1,2,3].iter();
for _i in &foo {} //~ ERROR E0277
}

View File

@ -0,0 +1,17 @@
error[E0277]: `&&std::slice::Iter<'_, {integer}>` is not an iterator
--> $DIR/suggest-remove-refs-4.rs:4:15
|
LL | for _i in &foo {}
| ^^^^ `&&std::slice::Iter<'_, {integer}>` is not an iterator
|
= help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>`
= note: required for `&&std::slice::Iter<'_, {integer}>` to implement `IntoIterator`
help: consider removing 2 leading `&`-references
|
LL ~ let foo = [1,2,3].iter();
LL ~ for _i in foo {}
|
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -2,14 +2,17 @@ error[E0277]: `&mut ()` is not a tuple
--> $DIR/issue-57404.rs:6:41
|
LL | handlers.unwrap().as_mut().call_mut(&mut ());
| -------- -^^^^^^
| | |
| | the trait `Tuple` is not implemented for `&mut ()`
| | help: consider removing the leading `&`-reference
| -------- ^^^^^^^ the trait `Tuple` is not implemented for `&mut ()`
| |
| required by a bound introduced by this call
|
note: required by a bound in `call_mut`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
help: consider removing the leading `&`-reference
|
LL - handlers.unwrap().as_mut().call_mut(&mut ());
LL + handlers.unwrap().as_mut().call_mut(());
|
error: aborting due to previous error