about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs32
-rw-r--r--src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed15
-rw-r--r--src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs15
-rw-r--r--src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr25
4 files changed, 80 insertions, 7 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 cae1509e640..5bc23a97517 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -882,6 +882,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             obligation.cause.code()
         {
             &parent_code
+        } else if let ObligationCauseCode::ItemObligation(_) = obligation.cause.code() {
+            obligation.cause.code()
         } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) =
             span.ctxt().outer_expn_data().kind
         {
@@ -930,10 +932,25 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
                     self.predicate_must_hold_modulo_regions(&obligation)
                 };
-                let imm_result = mk_result(trait_pred_and_imm_ref);
-                let mut_result = mk_result(trait_pred_and_mut_ref);
+                let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
+                let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
+
+                let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) =
+                if let ObligationCauseCode::ItemObligation(_) = obligation.cause.code()
+                    && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()
+                {
+                    (
+                        mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))),
+                        matches!(mutability, hir::Mutability::Mut),
+                    )
+                } else {
+                    (false, false)
+                };
 
-                if imm_result || mut_result {
+                if imm_ref_self_ty_satisfies_pred
+                    || mut_ref_self_ty_satisfies_pred
+                    || ref_inner_ty_satisfies_pred
+                {
                     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
@@ -973,7 +990,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             // }
                             // ```
 
-                            if imm_result && mut_result {
+                            if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred {
                                 err.span_suggestions(
                                     span.shrink_to_lo(),
                                     "consider borrowing here",
@@ -981,13 +998,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                     Applicability::MaybeIncorrect,
                                 );
                             } else {
+                                let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
                                 err.span_suggestion_verbose(
                                     span.shrink_to_lo(),
                                     &format!(
                                         "consider{} borrowing here",
-                                        if mut_result { " mutably" } else { "" }
+                                        if is_mut { " mutably" } else { "" }
                                     ),
-                                    format!("&{}", if mut_result { "mut " } else { "" }),
+                                    format!("&{}", if is_mut { "mut " } else { "" }),
                                     Applicability::MaybeIncorrect,
                                 );
                             }
@@ -1001,7 +1019,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
             try_borrowing(cause.derived.parent_trait_pred, &[])
         } else if let ObligationCauseCode::BindingObligation(_, _)
-        | ObligationCauseCode::ItemObligation(_) = code
+        | ObligationCauseCode::ItemObligation(..) = code
         {
             try_borrowing(poly_trait_pred, &never_suggest_borrow)
         } else {
diff --git a/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed
new file mode 100644
index 00000000000..e9b8a9caa48
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+#![allow(unused_variables)]
+
+fn foo(foo: &mut usize) {
+    todo!()
+}
+
+fn bar(bar: &usize) {
+    todo!()
+}
+
+fn main() {
+    foo(&mut Default::default()); //~ the trait bound `&mut usize: Default` is not satisfied
+    bar(&Default::default()); //~ the trait bound `&usize: Default` is not satisfied
+}
diff --git a/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs
new file mode 100644
index 00000000000..5fae21cccef
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+#![allow(unused_variables)]
+
+fn foo(foo: &mut usize) {
+    todo!()
+}
+
+fn bar(bar: &usize) {
+    todo!()
+}
+
+fn main() {
+    foo(Default::default()); //~ the trait bound `&mut usize: Default` is not satisfied
+    bar(Default::default()); //~ the trait bound `&usize: Default` is not satisfied
+}
diff --git a/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr
new file mode 100644
index 00000000000..b930d22a391
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `&mut usize: Default` is not satisfied
+  --> $DIR/suggest-adding-reference-to-trait-assoc-item.rs:13:9
+   |
+LL |     foo(Default::default());
+   |         ^^^^^^^^^^^^^^^^ expected an implementor of trait `Default`
+   |
+help: consider mutably borrowing here
+   |
+LL |     foo(&mut Default::default());
+   |         ++++
+
+error[E0277]: the trait bound `&usize: Default` is not satisfied
+  --> $DIR/suggest-adding-reference-to-trait-assoc-item.rs:14:9
+   |
+LL |     bar(Default::default());
+   |         ^^^^^^^^^^^^^^^^ expected an implementor of trait `Default`
+   |
+help: consider borrowing here
+   |
+LL |     bar(&Default::default());
+   |         +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.