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));
);
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
}
--> $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
--> $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`
--> $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
--> $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
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
--- /dev/null
+// run-rustfix
+fn main() {
+ let foo = [1,2,3].iter();
+ for _i in foo {} //~ ERROR E0277
+}
--- /dev/null
+// run-rustfix
+fn main() {
+ let foo = &[1,2,3].iter();
+ for _i in &foo {} //~ ERROR E0277
+}
--- /dev/null
+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`.
--> $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