Skip to content

Commit 0661c2d

Browse files
committed
suggest both immutable and mutable trait implementations
1 parent 4da89a1 commit 0661c2d

File tree

3 files changed

+70
-32
lines changed

3 files changed

+70
-32
lines changed

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

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -714,22 +714,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
714714
let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]);
715715

716716
// Try to apply the original trait binding obligation by borrowing.
717-
let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>,
717+
let mut try_borrowing = |new_imm_trait_ref: ty::TraitRef<'tcx>,
718+
new_mut_trait_ref: ty::TraitRef<'tcx>,
718719
expected_trait_ref: ty::TraitRef<'tcx>,
719-
mtbl: bool,
720720
blacklist: &[DefId]|
721721
-> bool {
722722
if blacklist.contains(&expected_trait_ref.def_id) {
723723
return false;
724724
}
725725

726-
let new_obligation = Obligation::new(
726+
let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
727727
ObligationCause::dummy(),
728728
param_env,
729-
ty::Binder::dummy(new_trait_ref).without_const().to_predicate(self.tcx),
730-
);
729+
ty::Binder::dummy(new_imm_trait_ref).without_const().to_predicate(self.tcx),
730+
));
731731

732-
if self.predicate_must_hold_modulo_regions(&new_obligation) {
732+
let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
733+
ObligationCause::dummy(),
734+
param_env,
735+
ty::Binder::dummy(new_mut_trait_ref).without_const().to_predicate(self.tcx),
736+
));
737+
738+
if imm_result || mut_result {
733739
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
734740
// We have a very specific type of error, where just borrowing this argument
735741
// 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> {
773779
// }
774780
// ```
775781

776-
err.span_suggestion(
777-
span,
778-
&format!(
779-
"consider{} borrowing here",
780-
if mtbl { " mutably" } else { "" }
781-
),
782-
format!("&{}{}", if mtbl { "mut " } else { "" }, snippet),
783-
Applicability::MaybeIncorrect,
784-
);
782+
if imm_result && mut_result {
783+
err.span_suggestions(
784+
span,
785+
"consider borrowing here",
786+
[format!("&{}", snippet), format!("&mut {}", snippet)].into_iter(),
787+
Applicability::MaybeIncorrect,
788+
);
789+
} else {
790+
err.span_suggestion(
791+
span,
792+
&format!(
793+
"consider{} borrowing here",
794+
if mut_result { " mutably" } else { "" }
795+
),
796+
format!("&{}{}", if mut_result { "mut " } else { "" }, snippet),
797+
Applicability::MaybeIncorrect,
798+
);
799+
}
785800
}
786801
return true;
787802
}
@@ -795,29 +810,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
795810
ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs);
796811
let new_mut_trait_ref =
797812
ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs);
798-
if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) {
799-
return true;
800-
} else {
801-
return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]);
802-
}
813+
return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]);
803814
} else if let ObligationCauseCode::BindingObligation(_, _)
804815
| ObligationCauseCode::ItemObligation(_) = &*code
805816
{
806-
if try_borrowing(
817+
return try_borrowing(
807818
ty::TraitRef::new(trait_ref.def_id, imm_substs),
819+
ty::TraitRef::new(trait_ref.def_id, mut_substs),
808820
trait_ref,
809-
false,
810821
&never_suggest_borrow[..],
811-
) {
812-
return true;
813-
} else {
814-
return try_borrowing(
815-
ty::TraitRef::new(trait_ref.def_id, mut_substs),
816-
trait_ref,
817-
true,
818-
&never_suggest_borrow[..],
819-
);
820-
}
822+
);
821823
} else {
822824
false
823825
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
trait Trait {}
2+
3+
struct S;
4+
5+
impl Trait for &S {}
6+
impl Trait for &mut S {}
7+
8+
fn foo<X: Trait>(_: X) {}
9+
10+
fn main() {
11+
let s = S;
12+
foo(s); //~ ERROR the trait bound `S: Trait` is not satisfied
13+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0277]: the trait bound `S: Trait` is not satisfied
2+
--> $DIR/suggest-both-imm-and-mut-trait-implementation.rs:12:9
3+
|
4+
LL | foo(s);
5+
| --- ^ expected an implementor of trait `Trait`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
note: required by a bound in `foo`
10+
--> $DIR/suggest-both-imm-and-mut-trait-implementation.rs:8:11
11+
|
12+
LL | fn foo<X: Trait>(_: X) {}
13+
| ^^^^^ required by this bound in `foo`
14+
help: consider borrowing here
15+
|
16+
LL | foo(&s);
17+
| ~~
18+
LL | foo(&mut s);
19+
| ~~~~~~
20+
21+
error: aborting due to previous error
22+
23+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)