about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTakayuki Maeda <takoyaki0316@gmail.com>2021-09-26 16:16:04 +0900
committerTakayuki Maeda <takoyaki0316@gmail.com>2021-09-26 16:43:44 +0900
commit0661c2de24521f76a1d014964ad4f60da7d14e46 (patch)
tree602fa970b6971e41b8e0a24acade240ec4033802
parent4da89a180facdecf168cbe0ddbc6bfbdd9f6e696 (diff)
downloadrust-0661c2de24521f76a1d014964ad4f60da7d14e46.tar.gz
rust-0661c2de24521f76a1d014964ad4f60da7d14e46.zip
suggest both immutable and mutable trait implementations
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs66
-rw-r--r--src/test/ui/suggestions/suggest-both-imm-and-mut-trait-implementation.rs13
-rw-r--r--src/test/ui/suggestions/suggest-both-imm-and-mut-trait-implementation.stderr23
3 files changed, 70 insertions, 32 deletions
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 9d1f409d69c..01fa3a50d81 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,
+                                "consider borrowing here",
+                                [format!("&{}", snippet), format!("&mut {}", snippet)].into_iter(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        } else {
+                            err.span_suggestion(
+                                span,
+                                &format!(
+                                    "consider{} borrowing here",
+                                    if mut_result { " mutably" } else { "" }
+                                ),
+                                format!("&{}{}", if mut_result { "mut " } else { "" }, snippet),
+                                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/suggestions/suggest-both-imm-and-mut-trait-implementation.rs b/src/test/ui/suggestions/suggest-both-imm-and-mut-trait-implementation.rs
new file mode 100644
index 00000000000..0a4f0b489fc
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-both-imm-and-mut-trait-implementation.rs
@@ -0,0 +1,13 @@
+trait Trait {}
+
+struct S;
+
+impl Trait for &S {}
+impl Trait for &mut S {}
+
+fn foo<X: Trait>(_: X) {}
+
+fn main() {
+    let s = S;
+    foo(s); //~ ERROR the trait bound `S: Trait` is not satisfied
+}
diff --git a/src/test/ui/suggestions/suggest-both-imm-and-mut-trait-implementation.stderr b/src/test/ui/suggestions/suggest-both-imm-and-mut-trait-implementation.stderr
new file mode 100644
index 00000000000..420f5e65cad
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-both-imm-and-mut-trait-implementation.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `S: Trait` is not satisfied
+  --> $DIR/suggest-both-imm-and-mut-trait-implementation.rs:12:9
+   |
+LL |     foo(s);
+   |     --- ^ expected an implementor of trait `Trait`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `foo`
+  --> $DIR/suggest-both-imm-and-mut-trait-implementation.rs:8:11
+   |
+LL | fn foo<X: Trait>(_: X) {}
+   |           ^^^^^ required by this bound in `foo`
+help: consider borrowing here
+   |
+LL |     foo(&s);
+   |         ~~
+LL |     foo(&mut s);
+   |         ~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.