about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs54
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6250.stderr5
-rw-r--r--tests/ui/suggestions/issue-109991.rs27
-rw-r--r--tests/ui/suggestions/issue-109991.stderr72
4 files changed, 139 insertions, 19 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 9ce03060e0f..47f3c6b8407 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -83,6 +83,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         self.annotate_expected_due_to_let_ty(err, expr, error);
+
+        if self.is_destruct_assignment_desugaring(expr) {
+            return;
+        }
         self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
         self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
@@ -1253,6 +1257,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    // Returns whether the given expression is a destruct assignment desugaring.
+    // For example, `(a, b) = (1, &2);`
+    // Here we try to find the pattern binding of the expression,
+    // `default_binding_modes` is false only for destruct assignment desugaring.
+    pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool {
+        if let hir::ExprKind::Path(hir::QPath::Resolved(
+            _,
+            hir::Path { res: hir::def::Res::Local(bind_hir_id), .. },
+        )) = expr.kind
+        {
+            let bind = self.tcx.hir().find(*bind_hir_id);
+            let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id));
+            if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. })) = bind &&
+                let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent {
+                    return true;
+                }
+        }
+        return false;
+    }
+
     /// This function is used to determine potential "simple" improvements or users' errors and
     /// provide them useful help. For example:
     ///
@@ -1443,6 +1467,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _,
                 &ty::Ref(_, checked, _),
             ) if self.can_sub(self.param_env, checked, expected) => {
+                let make_sugg = |start: Span, end: BytePos| {
+                    // skip `(` for tuples such as `(c) = (&123)`.
+                    // make sure we won't suggest like `(c) = 123)` which is incorrect.
+                    let sp = sm.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
+                                .map_or(start, |s| s.shrink_to_hi());
+                    Some((
+                        vec![(sp.with_hi(end), String::new())],
+                        "consider removing the borrow".to_string(),
+                        Applicability::MachineApplicable,
+                        true,
+                        true,
+                    ))
+                };
+
                 // We have `&T`, check if what was expected was `T`. If so,
                 // we may want to suggest removing a `&`.
                 if sm.is_imported(expr.span) {
@@ -1456,24 +1494,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .find(|&s| sp.contains(s))
                         && sm.is_span_accessible(call_span)
                     {
-                        return Some((
-                            vec![(sp.with_hi(call_span.lo()), String::new())],
-                            "consider removing the borrow".to_string(),
-                            Applicability::MachineApplicable,
-                            true,
-                            true,
-                        ));
+                        return make_sugg(sp, call_span.lo())
                     }
                     return None;
                 }
                 if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
-                    return Some((
-                        vec![(sp.with_hi(expr.span.lo()), String::new())],
-                        "consider removing the borrow".to_string(),
-                        Applicability::MachineApplicable,
-                        true,
-                        true,
-                    ));
+                    return make_sugg(sp, expr.span.lo())
                 }
             }
             (
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
index 4506d1550bd..db34e6bfa7b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
@@ -12,11 +12,6 @@ LL |     for reference in vec![1, 2, 3] {
 ...
 LL |         Some(reference) = cache.data.get(key) {
    |              ^^^^^^^^^ expected integer, found `&i32`
-   |
-help: consider dereferencing the borrow
-   |
-LL |         Some(*reference) = cache.data.get(key) {
-   |              +
 
 error[E0308]: mismatched types
   --> $DIR/ice-6250.rs:12:9
diff --git a/tests/ui/suggestions/issue-109991.rs b/tests/ui/suggestions/issue-109991.rs
new file mode 100644
index 00000000000..918451cb8ee
--- /dev/null
+++ b/tests/ui/suggestions/issue-109991.rs
@@ -0,0 +1,27 @@
+struct S {
+    a: usize,
+    b: usize,
+}
+
+fn main() {
+    let a: usize;
+    let b: usize;
+    let c: usize;
+
+    (c) = (&123); //~ ERROR mismatched types
+    (a, b) = (123, &mut 123); //~ ERROR mismatched types
+
+    let x: String;
+    (x,) = (1,); //~ ERROR mismatched types
+
+    let x: i32;
+    [x] = [&1]; //~ ERROR mismatched types
+
+    let x: &i32;
+    [x] = [1]; //~ ERROR mismatched types
+
+    let x = (1, &mut 2);
+    (a, b) = x; //~ ERROR mismatched types
+
+    S { a, b } = S { a: 1, b: &mut 2 }; //~ ERROR mismatched types
+}
diff --git a/tests/ui/suggestions/issue-109991.stderr b/tests/ui/suggestions/issue-109991.stderr
new file mode 100644
index 00000000000..bd21e4de648
--- /dev/null
+++ b/tests/ui/suggestions/issue-109991.stderr
@@ -0,0 +1,72 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:11:11
+   |
+LL |     let c: usize;
+   |            ----- expected due to this type
+LL |
+LL |     (c) = (&123);
+   |           ^^^^^^ expected `usize`, found `&{integer}`
+   |
+help: consider removing the borrow
+   |
+LL -     (c) = (&123);
+LL +     (c) = (123);
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:12:9
+   |
+LL |     let b: usize;
+   |            ----- expected due to this type
+...
+LL |     (a, b) = (123, &mut 123);
+   |         ^ expected `usize`, found `&mut {integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:15:6
+   |
+LL |     let x: String;
+   |            ------ expected due to this type
+LL |     (x,) = (1,);
+   |      ^ expected `String`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:18:6
+   |
+LL |     let x: i32;
+   |            --- expected due to this type
+LL |     [x] = [&1];
+   |      ^ expected `i32`, found `&{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:21:6
+   |
+LL |     let x: &i32;
+   |            ---- expected due to this type
+LL |     [x] = [1];
+   |      ^ expected `&i32`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:24:9
+   |
+LL |     let b: usize;
+   |            ----- expected due to this type
+...
+LL |     (a, b) = x;
+   |         ^ expected `usize`, found `&mut {integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:26:31
+   |
+LL |     S { a, b } = S { a: 1, b: &mut 2 };
+   |                               ^^^^^^ expected `usize`, found `&mut {integer}`
+   |
+help: consider removing the borrow
+   |
+LL -     S { a, b } = S { a: 1, b: &mut 2 };
+LL +     S { a, b } = S { a: 1, b: 2 };
+   |
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.