From e018c2400797f6b118a6f3a55993fd16bc29a035 Mon Sep 17 00:00:00 2001 From: Yukang Date: Mon, 7 Sep 2026 14:07:20 +0800 Subject: [PATCH 1/2] Add regression test for redundant shared reference suggestions --- ...undant-shared-reference-issue-133685.fixed | 35 +++++ ...redundant-shared-reference-issue-133685.rs | 35 +++++ ...ndant-shared-reference-issue-133685.stderr | 120 ++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 tests/ui/suggestions/redundant-shared-reference-issue-133685.fixed create mode 100644 tests/ui/suggestions/redundant-shared-reference-issue-133685.rs create mode 100644 tests/ui/suggestions/redundant-shared-reference-issue-133685.stderr diff --git a/tests/ui/suggestions/redundant-shared-reference-issue-133685.fixed b/tests/ui/suggestions/redundant-shared-reference-issue-133685.fixed new file mode 100644 index 0000000000000..64c60270775ab --- /dev/null +++ b/tests/ui/suggestions/redundant-shared-reference-issue-133685.fixed @@ -0,0 +1,35 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/133685. +//! Prefer removing an extra shared borrow over reborrowing an existing shared reference. + +//@ run-rustfix + +#![allow(unused_parens)] + +fn consume<'a>(_: impl IntoIterator) {} + +fn main() { + let a: Vec = Vec::new(); + let ref_a = &a; + let mut b: Vec = Vec::new(); + b.extend(&*ref_a); + //~^ ERROR is not an iterator + + consume(&*ref_a); + //~^ ERROR is not an iterator + consume((&*ref_a)); + //~^ ERROR is not an iterator + + let slice = &a[..]; + consume(&*slice); + //~^ ERROR is not an iterator + + // These still need a dereference: neither operand has the required shared-reference type. + let boxed = Box::new(a.clone()); + consume(&*boxed); + //~^ ERROR is not an iterator + + let mut values = a.clone(); + let mut_ref = &mut values; + consume(&*mut_ref); + //~^ ERROR is not an iterator +} diff --git a/tests/ui/suggestions/redundant-shared-reference-issue-133685.rs b/tests/ui/suggestions/redundant-shared-reference-issue-133685.rs new file mode 100644 index 0000000000000..4eed1ed4b6169 --- /dev/null +++ b/tests/ui/suggestions/redundant-shared-reference-issue-133685.rs @@ -0,0 +1,35 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/133685. +//! Prefer removing an extra shared borrow over reborrowing an existing shared reference. + +//@ run-rustfix + +#![allow(unused_parens)] + +fn consume<'a>(_: impl IntoIterator) {} + +fn main() { + let a: Vec = Vec::new(); + let ref_a = &a; + let mut b: Vec = Vec::new(); + b.extend(&ref_a); + //~^ ERROR is not an iterator + + consume(&ref_a); + //~^ ERROR is not an iterator + consume((&ref_a)); + //~^ ERROR is not an iterator + + let slice = &a[..]; + consume(&slice); + //~^ ERROR is not an iterator + + // These still need a dereference: neither operand has the required shared-reference type. + let boxed = Box::new(a.clone()); + consume(&boxed); + //~^ ERROR is not an iterator + + let mut values = a.clone(); + let mut_ref = &mut values; + consume(&mut_ref); + //~^ ERROR is not an iterator +} diff --git a/tests/ui/suggestions/redundant-shared-reference-issue-133685.stderr b/tests/ui/suggestions/redundant-shared-reference-issue-133685.stderr new file mode 100644 index 0000000000000..a26f7eb2265c6 --- /dev/null +++ b/tests/ui/suggestions/redundant-shared-reference-issue-133685.stderr @@ -0,0 +1,120 @@ +error[E0277]: `&&Vec` is not an iterator + --> $DIR/redundant-shared-reference-issue-133685.rs:14:14 + | +LL | b.extend(&ref_a); + | ------ ^^^^^^ `&&Vec` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&&Vec` + = note: required for `&&Vec` to implement `IntoIterator` +note: required by a bound in `extend` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL +help: consider dereferencing here + | +LL | b.extend(&*ref_a); + | + + +error[E0277]: `&&Vec` is not an iterator + --> $DIR/redundant-shared-reference-issue-133685.rs:17:13 + | +LL | consume(&ref_a); + | ------- ^^^^^^ `&&Vec` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&&Vec` + = note: required for `&&Vec` to implement `IntoIterator` +note: required by a bound in `consume` + --> $DIR/redundant-shared-reference-issue-133685.rs:8:24 + | +LL | fn consume<'a>(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `consume` +help: consider dereferencing here + | +LL | consume(&*ref_a); + | + + +error[E0277]: `&&Vec` is not an iterator + --> $DIR/redundant-shared-reference-issue-133685.rs:19:13 + | +LL | consume((&ref_a)); + | ------- ^^^^^^^^ `&&Vec` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&&Vec` + = note: required for `&&Vec` to implement `IntoIterator` +note: required by a bound in `consume` + --> $DIR/redundant-shared-reference-issue-133685.rs:8:24 + | +LL | fn consume<'a>(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `consume` +help: consider dereferencing here + | +LL | consume((&*ref_a)); + | + + +error[E0277]: `&&[i32]` is not an iterator + --> $DIR/redundant-shared-reference-issue-133685.rs:23:13 + | +LL | consume(&slice); + | ------- ^^^^^^ `&&[i32]` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&&[i32]` + = note: required for `&&[i32]` to implement `IntoIterator` +note: required by a bound in `consume` + --> $DIR/redundant-shared-reference-issue-133685.rs:8:24 + | +LL | fn consume<'a>(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `consume` +help: consider dereferencing here + | +LL | consume(&*slice); + | + + +error[E0277]: `&Box>` is not an iterator + --> $DIR/redundant-shared-reference-issue-133685.rs:28:13 + | +LL | consume(&boxed); + | ------- ^^^^^^ `&Box>` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&Box>` + = note: required for `&Box>` to implement `IntoIterator` +note: required by a bound in `consume` + --> $DIR/redundant-shared-reference-issue-133685.rs:8:24 + | +LL | fn consume<'a>(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `consume` +help: consider dereferencing here + | +LL | consume(&*boxed); + | + + +error[E0277]: `&&mut Vec` is not an iterator + --> $DIR/redundant-shared-reference-issue-133685.rs:33:13 + | +LL | consume(&mut_ref); + | ------- ^^^^^^^^ `&&mut Vec` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `&&mut Vec` + = note: required for `&&mut Vec` to implement `IntoIterator` +note: required by a bound in `consume` + --> $DIR/redundant-shared-reference-issue-133685.rs:8:24 + | +LL | fn consume<'a>(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `consume` +help: consider dereferencing here + | +LL | consume(&*mut_ref); + | + + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. From fb197434d205eba41ec97dd5f864f2ce97e744ed Mon Sep 17 00:00:00 2001 From: Yukang Date: Mon, 7 Sep 2026 14:17:15 +0800 Subject: [PATCH 2/2] Prefer removing a redundant shared reference over reborrowing --- .../traits/fulfillment_errors.rs | 14 +++-- .../src/error_reporting/traits/suggestions.rs | 11 ++++ ...undant-shared-reference-issue-133685.fixed | 19 ++++-- ...redundant-shared-reference-issue-133685.rs | 11 ++++ ...ndant-shared-reference-issue-133685.stderr | 61 +++++++++++++------ 5 files changed, 87 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 7788a1bb62a09..d8a22e745bcc2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -478,7 +478,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { leaf_trait_predicate, ); suggested |= - self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate); + self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate) + || self.suggest_remove_reference( + &obligation, + &mut err, + leaf_trait_predicate, + ); + suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate); suggested |= self.suggest_cast_to_fn_pointer( @@ -488,11 +494,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { main_trait_predicate, span, ); - suggested |= self.suggest_remove_reference( - &obligation, - &mut err, - leaf_trait_predicate, - ); + suggested |= self.suggest_semicolon_removal( &obligation, &mut err, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index b8e4521451a25..2fe04a3c78384 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -780,6 +780,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if span.in_external_macro(self.tcx.sess.source_map()) { return false; } + + // For a shared reference, prefer removing the outer `&` over suggesting + // `&*reference`. Keep the reborrow for `&mut T` and smart pointers. + if is_under_ref.is_some() + && steps == 1 + && matches!(base_ty.kind(), ty::Ref(_, _, hir::Mutability::Not)) + && !expr.span.from_expansion() + && self.suggest_remove_reference(obligation, err, real_trait_pred) + { + return true; + } let derefs = "*".repeat(steps); let msg = "consider dereferencing here"; diff --git a/tests/ui/suggestions/redundant-shared-reference-issue-133685.fixed b/tests/ui/suggestions/redundant-shared-reference-issue-133685.fixed index 64c60270775ab..2c7d21d7788cc 100644 --- a/tests/ui/suggestions/redundant-shared-reference-issue-133685.fixed +++ b/tests/ui/suggestions/redundant-shared-reference-issue-133685.fixed @@ -7,20 +7,25 @@ fn consume<'a>(_: impl IntoIterator) {} +trait Value {} +struct Source; +impl Value for &Source {} +fn consume_value(_: impl Value) {} + fn main() { let a: Vec = Vec::new(); let ref_a = &a; let mut b: Vec = Vec::new(); - b.extend(&*ref_a); + b.extend(ref_a); //~^ ERROR is not an iterator - consume(&*ref_a); + consume(ref_a); //~^ ERROR is not an iterator - consume((&*ref_a)); + consume((ref_a)); //~^ ERROR is not an iterator let slice = &a[..]; - consume(&*slice); + consume(slice); //~^ ERROR is not an iterator // These still need a dereference: neither operand has the required shared-reference type. @@ -32,4 +37,10 @@ fn main() { let mut_ref = &mut values; consume(&*mut_ref); //~^ ERROR is not an iterator + + // Also cover a direct trait bound without the Iterator-to-IntoIterator blanket impl. + let source = Source; + let shared = &source; + consume_value(shared); + //~^ ERROR the trait bound } diff --git a/tests/ui/suggestions/redundant-shared-reference-issue-133685.rs b/tests/ui/suggestions/redundant-shared-reference-issue-133685.rs index 4eed1ed4b6169..38f699a8dfe85 100644 --- a/tests/ui/suggestions/redundant-shared-reference-issue-133685.rs +++ b/tests/ui/suggestions/redundant-shared-reference-issue-133685.rs @@ -7,6 +7,11 @@ fn consume<'a>(_: impl IntoIterator) {} +trait Value {} +struct Source; +impl Value for &Source {} +fn consume_value(_: impl Value) {} + fn main() { let a: Vec = Vec::new(); let ref_a = &a; @@ -32,4 +37,10 @@ fn main() { let mut_ref = &mut values; consume(&mut_ref); //~^ ERROR is not an iterator + + // Also cover a direct trait bound without the Iterator-to-IntoIterator blanket impl. + let source = Source; + let shared = &source; + consume_value(&shared); + //~^ ERROR the trait bound } diff --git a/tests/ui/suggestions/redundant-shared-reference-issue-133685.stderr b/tests/ui/suggestions/redundant-shared-reference-issue-133685.stderr index a26f7eb2265c6..e1115c2c91b3d 100644 --- a/tests/ui/suggestions/redundant-shared-reference-issue-133685.stderr +++ b/tests/ui/suggestions/redundant-shared-reference-issue-133685.stderr @@ -1,5 +1,5 @@ error[E0277]: `&&Vec` is not an iterator - --> $DIR/redundant-shared-reference-issue-133685.rs:14:14 + --> $DIR/redundant-shared-reference-issue-133685.rs:19:14 | LL | b.extend(&ref_a); | ------ ^^^^^^ `&&Vec` is not an iterator @@ -10,13 +10,14 @@ LL | b.extend(&ref_a); = note: required for `&&Vec` to implement `IntoIterator` note: required by a bound in `extend` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL -help: consider dereferencing here +help: consider removing the leading `&`-reference + | +LL - b.extend(&ref_a); +LL + b.extend(ref_a); | -LL | b.extend(&*ref_a); - | + error[E0277]: `&&Vec` is not an iterator - --> $DIR/redundant-shared-reference-issue-133685.rs:17:13 + --> $DIR/redundant-shared-reference-issue-133685.rs:22:13 | LL | consume(&ref_a); | ------- ^^^^^^ `&&Vec` is not an iterator @@ -30,13 +31,14 @@ note: required by a bound in `consume` | LL | fn consume<'a>(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `consume` -help: consider dereferencing here +help: consider removing the leading `&`-reference + | +LL - consume(&ref_a); +LL + consume(ref_a); | -LL | consume(&*ref_a); - | + error[E0277]: `&&Vec` is not an iterator - --> $DIR/redundant-shared-reference-issue-133685.rs:19:13 + --> $DIR/redundant-shared-reference-issue-133685.rs:24:13 | LL | consume((&ref_a)); | ------- ^^^^^^^^ `&&Vec` is not an iterator @@ -50,13 +52,14 @@ note: required by a bound in `consume` | LL | fn consume<'a>(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `consume` -help: consider dereferencing here +help: consider removing the leading `&`-reference + | +LL - consume((&ref_a)); +LL + consume((ref_a)); | -LL | consume((&*ref_a)); - | + error[E0277]: `&&[i32]` is not an iterator - --> $DIR/redundant-shared-reference-issue-133685.rs:23:13 + --> $DIR/redundant-shared-reference-issue-133685.rs:28:13 | LL | consume(&slice); | ------- ^^^^^^ `&&[i32]` is not an iterator @@ -70,13 +73,14 @@ note: required by a bound in `consume` | LL | fn consume<'a>(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `consume` -help: consider dereferencing here +help: consider removing the leading `&`-reference + | +LL - consume(&slice); +LL + consume(slice); | -LL | consume(&*slice); - | + error[E0277]: `&Box>` is not an iterator - --> $DIR/redundant-shared-reference-issue-133685.rs:28:13 + --> $DIR/redundant-shared-reference-issue-133685.rs:33:13 | LL | consume(&boxed); | ------- ^^^^^^ `&Box>` is not an iterator @@ -96,7 +100,7 @@ LL | consume(&*boxed); | + error[E0277]: `&&mut Vec` is not an iterator - --> $DIR/redundant-shared-reference-issue-133685.rs:33:13 + --> $DIR/redundant-shared-reference-issue-133685.rs:38:13 | LL | consume(&mut_ref); | ------- ^^^^^^^^ `&&mut Vec` is not an iterator @@ -115,6 +119,25 @@ help: consider dereferencing here LL | consume(&*mut_ref); | + -error: aborting due to 6 previous errors +error[E0277]: the trait bound `&&Source: Value` is not satisfied + --> $DIR/redundant-shared-reference-issue-133685.rs:44:19 + | +LL | consume_value(&shared); + | ------------- ^^^^^^^ the trait `Value` is not implemented for `&&Source` + | | + | required by a bound introduced by this call + | +note: required by a bound in `consume_value` + --> $DIR/redundant-shared-reference-issue-133685.rs:13:26 + | +LL | fn consume_value(_: impl Value) {} + | ^^^^^ required by this bound in `consume_value` +help: consider removing the leading `&`-reference + | +LL - consume_value(&shared); +LL + consume_value(shared); + | + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0277`.