diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9d1f409d69c66..2a51e01471398 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -714,22 +714,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]); // Try to apply the original trait binding obligation by borrowing. - let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>, + let mut try_borrowing = |new_imm_trait_ref: ty::TraitRef<'tcx>, + new_mut_trait_ref: ty::TraitRef<'tcx>, expected_trait_ref: ty::TraitRef<'tcx>, - mtbl: bool, blacklist: &[DefId]| -> bool { if blacklist.contains(&expected_trait_ref.def_id) { return false; } - let new_obligation = Obligation::new( + let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new( ObligationCause::dummy(), param_env, - ty::Binder::dummy(new_trait_ref).without_const().to_predicate(self.tcx), - ); + ty::Binder::dummy(new_imm_trait_ref).without_const().to_predicate(self.tcx), + )); - if self.predicate_must_hold_modulo_regions(&new_obligation) { + let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new( + ObligationCause::dummy(), + param_env, + ty::Binder::dummy(new_mut_trait_ref).without_const().to_predicate(self.tcx), + )); + + if imm_result || mut_result { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { // We have a very specific type of error, where just borrowing this argument // might solve the problem. In cases like this, the important part is the @@ -773,15 +779,24 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // } // ``` - err.span_suggestion( - span, - &format!( - "consider{} borrowing here", - if mtbl { " mutably" } else { "" } - ), - format!("&{}{}", if mtbl { "mut " } else { "" }, snippet), - Applicability::MaybeIncorrect, - ); + if imm_result && mut_result { + err.span_suggestions( + span.shrink_to_lo(), + "consider borrowing here", + ["&".to_string(), "&mut ".to_string()].into_iter(), + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!( + "consider{} borrowing here", + if mut_result { " mutably" } else { "" } + ), + format!("&{}", if mut_result { "mut " } else { "" }), + Applicability::MaybeIncorrect, + ); + } } return true; } @@ -795,29 +810,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs); let new_mut_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs); - if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) { - return true; - } else { - return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]); - } + return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]); } else if let ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ItemObligation(_) = &*code { - if try_borrowing( + return try_borrowing( ty::TraitRef::new(trait_ref.def_id, imm_substs), + ty::TraitRef::new(trait_ref.def_id, mut_substs), trait_ref, - false, &never_suggest_borrow[..], - ) { - return true; - } else { - return try_borrowing( - ty::TraitRef::new(trait_ref.def_id, mut_substs), - trait_ref, - true, - &never_suggest_borrow[..], - ); - } + ); } else { false } diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr index 2538b5533a6d6..1d0554ad0477f 100644 --- a/src/test/ui/derives/deriving-copyclone.stderr +++ b/src/test/ui/derives/deriving-copyclone.stderr @@ -2,10 +2,8 @@ error[E0277]: the trait bound `C: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:31:13 | LL | is_copy(B { a: 1, b: C }); - | ------- ^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Copy` - | | help: consider borrowing here: `&B { a: 1, b: C }` + | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy` + | | | required by a bound introduced by this call | note: required because of the requirements on the impl of `Copy` for `B` @@ -19,15 +17,17 @@ note: required by a bound in `is_copy` LL | fn is_copy(_: T) {} | ^^^^ required by this bound in `is_copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | is_copy(&B { a: 1, b: C }); + | + error[E0277]: the trait bound `C: Clone` is not satisfied --> $DIR/deriving-copyclone.rs:32:14 | LL | is_clone(B { a: 1, b: C }); - | -------- ^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Clone` - | | help: consider borrowing here: `&B { a: 1, b: C }` + | -------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone` + | | | required by a bound introduced by this call | note: required because of the requirements on the impl of `Clone` for `B` @@ -41,15 +41,17 @@ note: required by a bound in `is_clone` LL | fn is_clone(_: T) {} | ^^^^^ required by this bound in `is_clone` = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | is_clone(&B { a: 1, b: C }); + | + error[E0277]: the trait bound `D: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:35:13 | LL | is_copy(B { a: 1, b: D }); - | ------- ^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Copy` - | | help: consider borrowing here: `&B { a: 1, b: D }` + | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy` + | | | required by a bound introduced by this call | note: required because of the requirements on the impl of `Copy` for `B` @@ -63,6 +65,10 @@ note: required by a bound in `is_copy` LL | fn is_copy(_: T) {} | ^^^^ required by this bound in `is_copy` = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider borrowing here + | +LL | is_copy(&B { a: 1, b: D }); + | + error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index ce3ab6b599864..5a67aead75a73 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -2,10 +2,7 @@ error[E0277]: the size for values of type `dyn Iterator` cann --> $DIR/issue-20605.rs:2:17 | LL | for item in *things { *item = 0 } - | ^^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider mutably borrowing here: `&mut *things` + | ^^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `dyn Iterator: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `dyn Iterator` @@ -14,6 +11,10 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider mutably borrowing here + | +LL | for item in &mut *things { *item = 0 } + | ++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr index 71779ecb7299f..001af27b2484e 100644 --- a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr +++ b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr @@ -22,10 +22,8 @@ error[E0277]: the trait bound `S: Trait` is not satisfied --> $DIR/imm-ref-trait-object-literal.rs:13:7 | LL | foo(s); - | --- ^ - | | | - | | expected an implementor of trait `Trait` - | | help: consider mutably borrowing here: `&mut s` + | --- ^ expected an implementor of trait `Trait` + | | | required by a bound introduced by this call | note: required by a bound in `foo` @@ -33,6 +31,10 @@ note: required by a bound in `foo` | LL | fn foo(_: X) {} | ^^^^^ required by this bound in `foo` +help: consider mutably borrowing here + | +LL | foo(&mut s); + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-62843.stderr b/src/test/ui/suggestions/issue-62843.stderr index 93251b2c8dbfc..29ba39cbe109c 100644 --- a/src/test/ui/suggestions/issue-62843.stderr +++ b/src/test/ui/suggestions/issue-62843.stderr @@ -2,14 +2,16 @@ error[E0277]: expected a `FnMut<(char,)>` closure, found `String` --> $DIR/issue-62843.rs:4:32 | LL | println!("{:?}", line.find(pattern)); - | ---- ^^^^^^^ - | | | - | | expected an implementor of trait `Pattern<'_>` - | | help: consider borrowing here: `&pattern` + | ---- ^^^^^^^ expected an implementor of trait `Pattern<'_>` + | | | required by a bound introduced by this call | = note: the trait bound `String: Pattern<'_>` is not satisfied = note: required because of the requirements on the impl of `Pattern<'_>` for `String` +help: consider borrowing here + | +LL | println!("{:?}", line.find(&pattern)); + | + error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-84973-2.stderr b/src/test/ui/suggestions/issue-84973-2.stderr index c1a7a2e101d62..2c54ea6724505 100644 --- a/src/test/ui/suggestions/issue-84973-2.stderr +++ b/src/test/ui/suggestions/issue-84973-2.stderr @@ -2,10 +2,8 @@ error[E0277]: the trait bound `i32: Tr` is not satisfied --> $DIR/issue-84973-2.rs:11:9 | LL | foo(a); - | --- ^ - | | | - | | expected an implementor of trait `Tr` - | | help: consider mutably borrowing here: `&mut a` + | --- ^ expected an implementor of trait `Tr` + | | | required by a bound introduced by this call | note: required by a bound in `foo` @@ -13,6 +11,10 @@ note: required by a bound in `foo` | LL | fn foo(i: T) {} | ^^ required by this bound in `foo` +help: consider mutably borrowing here + | +LL | foo(&mut a); + | ++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-84973-negative.stderr b/src/test/ui/suggestions/issue-84973-negative.stderr index 14b32d8515cd7..1f33374eb29db 100644 --- a/src/test/ui/suggestions/issue-84973-negative.stderr +++ b/src/test/ui/suggestions/issue-84973-negative.stderr @@ -16,10 +16,8 @@ error[E0277]: the trait bound `f32: Tr` is not satisfied --> $DIR/issue-84973-negative.rs:11:9 | LL | bar(b); - | --- ^ - | | | - | | expected an implementor of trait `Tr` - | | help: consider borrowing here: `&b` + | --- ^ expected an implementor of trait `Tr` + | | | required by a bound introduced by this call | note: required by a bound in `bar` @@ -27,6 +25,10 @@ note: required by a bound in `bar` | LL | fn bar(t: T) {} | ^^ required by this bound in `bar` +help: consider borrowing here + | +LL | bar(&b); + | + error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-84973.stderr b/src/test/ui/suggestions/issue-84973.stderr index 169d0cccb43ef..16a28c73aa724 100644 --- a/src/test/ui/suggestions/issue-84973.stderr +++ b/src/test/ui/suggestions/issue-84973.stderr @@ -2,10 +2,8 @@ error[E0277]: the trait bound `Fancy: SomeTrait` is not satisfied --> $DIR/issue-84973.rs:6:24 | LL | let o = Other::new(f); - | ---------- ^ - | | | - | | expected an implementor of trait `SomeTrait` - | | help: consider borrowing here: `&f` + | ---------- ^ expected an implementor of trait `SomeTrait` + | | | required by a bound introduced by this call | note: required by `Other::<'a, G>::new` @@ -13,6 +11,10 @@ note: required by `Other::<'a, G>::new` | LL | pub fn new(g: G) -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | let o = Other::new(&f); + | + error: aborting due to previous error diff --git a/src/test/ui/suggestions/slice-issue-87994.stderr b/src/test/ui/suggestions/slice-issue-87994.stderr index 018f62e783daf..0275fd475d8c6 100644 --- a/src/test/ui/suggestions/slice-issue-87994.stderr +++ b/src/test/ui/suggestions/slice-issue-87994.stderr @@ -2,10 +2,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation --> $DIR/slice-issue-87994.rs:3:12 | LL | for _ in v[1..] { - | ^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider borrowing here: `&v[1..]` + | ^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `[i32]: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `[i32]` @@ -14,15 +11,18 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for _ in &v[1..] { + | + +LL | for _ in &mut v[1..] { + | ++++ error[E0277]: `[i32]` is not an iterator --> $DIR/slice-issue-87994.rs:3:12 | LL | for _ in v[1..] { - | ^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider borrowing here: `&v[1..]` + | ^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `[i32]: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `[i32]` @@ -31,15 +31,18 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for _ in &v[1..] { + | + +LL | for _ in &mut v[1..] { + | ++++ error[E0277]: the size for values of type `[K]` cannot be known at compilation time --> $DIR/slice-issue-87994.rs:11:13 | LL | for i2 in v2[1..] { - | ^^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider borrowing here: `&v2[1..]` + | ^^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `[K]: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `[K]` @@ -48,15 +51,18 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for i2 in &v2[1..] { + | + +LL | for i2 in &mut v2[1..] { + | ++++ error[E0277]: `[K]` is not an iterator --> $DIR/slice-issue-87994.rs:11:13 | LL | for i2 in v2[1..] { - | ^^^^^^^ - | | - | expected an implementor of trait `IntoIterator` - | help: consider borrowing here: `&v2[1..]` + | ^^^^^^^ expected an implementor of trait `IntoIterator` | = note: the trait bound `[K]: IntoIterator` is not satisfied = note: required because of the requirements on the impl of `IntoIterator` for `[K]` @@ -65,6 +71,12 @@ note: required by `into_iter` | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider borrowing here + | +LL | for i2 in &v2[1..] { + | + +LL | for i2 in &mut v2[1..] { + | ++++ error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs new file mode 100644 index 0000000000000..a62669d5b2d8f --- /dev/null +++ b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs @@ -0,0 +1,23 @@ +trait Trait {} + +struct A; +struct B; +struct C; + +impl Trait for &A {} +impl Trait for &mut A {} + +impl Trait for &B {} + +impl Trait for &mut C {} + +fn foo(_: X) {} + +fn main() { + let a = A; + let b = B; + let c = C; + foo(a); //~ ERROR the trait bound `A: Trait` is not satisfied + foo(b); //~ ERROR the trait bound `B: Trait` is not satisfied + foo(c); //~ ERROR the trait bound `C: Trait` is not satisfied +} diff --git a/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr new file mode 100644 index 0000000000000..6583cabe18489 --- /dev/null +++ b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr @@ -0,0 +1,59 @@ +error[E0277]: the trait bound `A: Trait` is not satisfied + --> $DIR/suggest-imm-mut-trait-implementations.rs:20:9 + | +LL | foo(a); + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11 + | +LL | fn foo(_: X) {} + | ^^^^^ required by this bound in `foo` +help: consider borrowing here + | +LL | foo(&a); + | + +LL | foo(&mut a); + | ++++ + +error[E0277]: the trait bound `B: Trait` is not satisfied + --> $DIR/suggest-imm-mut-trait-implementations.rs:21:9 + | +LL | foo(b); + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11 + | +LL | fn foo(_: X) {} + | ^^^^^ required by this bound in `foo` +help: consider borrowing here + | +LL | foo(&b); + | + + +error[E0277]: the trait bound `C: Trait` is not satisfied + --> $DIR/suggest-imm-mut-trait-implementations.rs:22:9 + | +LL | foo(c); + | --- ^ expected an implementor of trait `Trait` + | | + | required by a bound introduced by this call + | +note: required by a bound in `foo` + --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11 + | +LL | fn foo(_: X) {} + | ^^^^^ required by this bound in `foo` +help: consider mutably borrowing here + | +LL | foo(&mut c); + | ++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr index 790e2a81c3a8c..8059a8ca71e43 100644 --- a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -61,10 +61,8 @@ error[E0277]: `dummy2::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:48:13 | LL | is_send(Box::new(TestType)); - | ------- ^^^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Send` - | | help: consider borrowing here: `&Box::new(TestType)` + | ------- ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Send` + | | | required by a bound introduced by this call | = note: the trait bound `dummy2::TestType: Send` is not satisfied @@ -75,6 +73,10 @@ note: required by a bound in `is_send` | LL | fn is_send(_: T) {} | ^^^^ required by this bound in `is_send` +help: consider borrowing here + | +LL | is_send(&Box::new(TestType)); + | + error[E0277]: `dummy3::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:56:13 @@ -102,10 +104,8 @@ error[E0277]: `main::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:66:13 | LL | is_sync(Outer2(TestType)); - | ------- ^^^^^^^^^^^^^^^^ - | | | - | | expected an implementor of trait `Sync` - | | help: consider borrowing here: `&Outer2(TestType)` + | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Sync` + | | | required by a bound introduced by this call | = note: the trait bound `main::TestType: Sync` is not satisfied @@ -119,6 +119,12 @@ note: required by a bound in `is_sync` | LL | fn is_sync(_: T) {} | ^^^^ required by this bound in `is_sync` +help: consider borrowing here + | +LL | is_sync(&Outer2(TestType)); + | + +LL | is_sync(&mut Outer2(TestType)); + | ++++ error: aborting due to 7 previous errors