about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs19
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs47
-rw-r--r--src/test/ui/suggestions/format-borrow.stderr16
-rw-r--r--src/test/ui/suggestions/issue-102892.rs25
-rw-r--r--src/test/ui/suggestions/issue-102892.stderr57
5 files changed, 160 insertions, 4 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 2974ac97f23..be14234afe2 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -714,7 +714,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
-    ) -> Option<(Span, String, String, Applicability, bool /* verbose */)> {
+    ) -> Option<(
+        Span,
+        String,
+        String,
+        Applicability,
+        bool, /* verbose */
+        bool, /* suggest `&` or `&mut` type annotation */
+    )> {
         let sess = self.sess();
         let sp = expr.span;
 
@@ -746,6 +753,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     String::new(),
                                     Applicability::MachineApplicable,
                                     true,
+                                    false,
                                 ));
                             }
                         }
@@ -760,6 +768,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     "b".to_string(),
                                     Applicability::MachineApplicable,
                                     true,
+                                    false,
                                 ));
                     }
                 }
@@ -817,6 +826,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 sugg.2,
                                 Applicability::MachineApplicable,
                                 false,
+                                false,
                             ));
                         }
 
@@ -844,6 +854,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 format!("{prefix}&mut {sugg_expr}"),
                                 Applicability::MachineApplicable,
                                 false,
+                                false,
                             ),
                             hir::Mutability::Not => (
                                 sp,
@@ -851,6 +862,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 format!("{prefix}&{sugg_expr}"),
                                 Applicability::MachineApplicable,
                                 false,
+                                false,
                             ),
                         });
                     }
@@ -880,6 +892,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             String::new(),
                             Applicability::MachineApplicable,
                             true,
+                            true
                         ));
                     }
                     return None;
@@ -893,6 +906,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         String::new(),
                         Applicability::MachineApplicable,
                         true,
+                        true,
                     ));
                 }
             }
@@ -959,6 +973,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             src,
                             applicability,
                             true,
+                            false,
                         ));
                     }
                 }
@@ -999,6 +1014,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 Applicability::MachineApplicable
                             },
                             true,
+                            false,
                         ));
                     }
 
@@ -1050,6 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             suggestion,
                             Applicability::MachineApplicable,
                             true,
+                            false,
                         ));
                     }
                 }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index cd2e41aff0f..4db9c56f98f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -327,7 +327,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
     ) -> bool {
         let expr = expr.peel_blocks();
-        if let Some((sp, msg, suggestion, applicability, verbose)) =
+        if let Some((sp, msg, suggestion, applicability, verbose, annotation)) =
             self.check_ref(expr, found, expected)
         {
             if verbose {
@@ -335,9 +335,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 err.span_suggestion(sp, &msg, suggestion, applicability);
             }
+            if annotation {
+                let suggest_annotation = match expr.peel_drop_temps().kind {
+                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, _) => "&",
+                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mut, _) => "&mut ",
+                    _ => return true,
+                };
+                let mut tuple_indexes = Vec::new();
+                let mut expr_id = expr.hir_id;
+                for (parent_id, node) in self.tcx.hir().parent_iter(expr.hir_id) {
+                    match node {
+                        Node::Expr(&Expr { kind: ExprKind::Tup(subs), .. }) => {
+                            tuple_indexes.push(
+                                subs.iter()
+                                    .enumerate()
+                                    .find(|(_, sub_expr)| sub_expr.hir_id == expr_id)
+                                    .unwrap()
+                                    .0,
+                            );
+                            expr_id = parent_id;
+                        }
+                        Node::Local(local) => {
+                            if let Some(mut ty) = local.ty {
+                                while let Some(index) = tuple_indexes.pop() {
+                                    match ty.kind {
+                                        TyKind::Tup(tys) => ty = &tys[index],
+                                        _ => return true,
+                                    }
+                                }
+                                let annotation_span = ty.span;
+                                err.span_suggestion(
+                                    annotation_span.with_hi(annotation_span.lo()),
+                                    format!("alternatively, consider changing the type annotation"),
+                                    suggest_annotation,
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            break;
+                        }
+                        _ => break,
+                    }
+                }
+            }
             return true;
-        } else if self.suggest_else_fn_with_closure(err, expr, found, expected)
-        {
+        } else if self.suggest_else_fn_with_closure(err, expr, found, expected) {
             return true;
         } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
             && let ty::FnDef(def_id, ..) = &found.kind()
diff --git a/src/test/ui/suggestions/format-borrow.stderr b/src/test/ui/suggestions/format-borrow.stderr
index fac6a5a5f48..8ed2b9c9a63 100644
--- a/src/test/ui/suggestions/format-borrow.stderr
+++ b/src/test/ui/suggestions/format-borrow.stderr
@@ -11,6 +11,10 @@ help: consider removing the borrow
 LL -     let a: String = &String::from("a");
 LL +     let a: String = String::from("a");
    |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let a: &String = &String::from("a");
+   |            +
 
 error[E0308]: mismatched types
   --> $DIR/format-borrow.rs:4:21
@@ -25,6 +29,10 @@ help: consider removing the borrow
 LL -     let b: String = &format!("b");
 LL +     let b: String = format!("b");
    |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let b: &String = &format!("b");
+   |            +
 
 error[E0308]: mismatched types
   --> $DIR/format-borrow.rs:6:21
@@ -39,6 +47,10 @@ help: consider removing the borrow
 LL -     let c: String = &mut format!("c");
 LL +     let c: String = format!("c");
    |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let c: &mut String = &mut format!("c");
+   |            ++++
 
 error[E0308]: mismatched types
   --> $DIR/format-borrow.rs:8:21
@@ -53,6 +65,10 @@ help: consider removing the borrow
 LL -     let d: String = &mut (format!("d"));
 LL +     let d: String = format!("d"));
    |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let d: &mut String = &mut (format!("d"));
+   |            ++++
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/suggestions/issue-102892.rs b/src/test/ui/suggestions/issue-102892.rs
new file mode 100644
index 00000000000..c1a791d8d85
--- /dev/null
+++ b/src/test/ui/suggestions/issue-102892.rs
@@ -0,0 +1,25 @@
+#![allow(dead_code, unused_variables)]
+
+use std::sync::Arc;
+
+#[derive(Debug)]
+struct A;
+#[derive(Debug)]
+struct B;
+
+fn process_without_annot(arc: &Arc<(A, B)>) {
+    let (a, b) = **arc; // suggests putting `&**arc` here; with that, fixed!
+}
+
+fn process_with_annot(arc: &Arc<(A, B)>) {
+    let (a, b): (A, B) = &**arc; // suggests putting `&**arc` here too
+    //~^ ERROR mismatched types
+}
+
+fn process_with_tuple_annot(mutation: &mut (A, B), arc: &Arc<(A, B)>) {
+    let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+    //~^ ERROR mismatched types
+    //~| ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-102892.stderr b/src/test/ui/suggestions/issue-102892.stderr
new file mode 100644
index 00000000000..a3dbc7cb861
--- /dev/null
+++ b/src/test/ui/suggestions/issue-102892.stderr
@@ -0,0 +1,57 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-102892.rs:15:26
+   |
+LL |     let (a, b): (A, B) = &**arc; // suggests putting `&**arc` here too
+   |                 ------   ^^^^^^ expected tuple, found `&(A, B)`
+   |                 |
+   |                 expected due to this
+   |
+   = note:  expected tuple `(A, B)`
+           found reference `&(A, B)`
+help: consider removing the borrow
+   |
+LL -     let (a, b): (A, B) = &**arc; // suggests putting `&**arc` here too
+LL +     let (a, b): (A, B) = **arc; // suggests putting `&**arc` here too
+   |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let (a, b): &(A, B) = &**arc; // suggests putting `&**arc` here too
+   |                 +
+
+error[E0308]: mismatched types
+  --> $DIR/issue-102892.rs:20:32
+   |
+LL |     let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |                                ^^^^^^^^^^^^^^ expected tuple, found `&mut (A, B)`
+   |
+   = note:          expected tuple `(A, B)`
+           found mutable reference `&mut (A, B)`
+help: consider removing the borrow
+   |
+LL -     let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+LL +     let (a, b): ((A, B), A) = (*mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let (a, b): (&mut (A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |                  ++++
+
+error[E0308]: mismatched types
+  --> $DIR/issue-102892.rs:20:48
+   |
+LL |     let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |                                                ^^^^^^^^^^ expected struct `A`, found `&A`
+   |
+help: consider removing the borrow
+   |
+LL -     let (a, b): ((A, B), A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+LL +     let (a, b): ((A, B), A) = (&mut *mutation, (**arc).0); // suggests putting `&**arc` here too
+   |
+help: alternatively, consider changing the type annotation
+   |
+LL |     let (a, b): ((A, B), &A) = (&mut *mutation, &(**arc).0); // suggests putting `&**arc` here too
+   |                          +
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.