about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs16
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs20
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs81
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs57
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs18
-rw-r--r--compiler/rustc_typeck/src/check/op.rs2
-rw-r--r--src/test/ui/dst/dst-bad-assign-3.stderr4
-rw-r--r--src/test/ui/dst/dst-bad-assign.stderr4
-rw-r--r--src/test/ui/error-codes/E0070.rs1
-rw-r--r--src/test/ui/error-codes/E0070.stderr11
-rw-r--r--src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs8
-rw-r--r--src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr6
-rw-r--r--src/test/ui/impl-trait/impl-trait-in-macro.stderr2
-rw-r--r--src/test/ui/impl-trait/universal-two-impl-traits.stderr1
-rw-r--r--src/test/ui/integral-variable-unification-error.rs6
-rw-r--r--src/test/ui/integral-variable-unification-error.stderr7
-rw-r--r--src/test/ui/issues/issue-13407.rs1
-rw-r--r--src/test/ui/issues/issue-13407.stderr10
-rw-r--r--src/test/ui/issues/issue-2951.stderr1
-rw-r--r--src/test/ui/issues/issue-53348.rs2
-rw-r--r--src/test/ui/issues/issue-53348.stderr3
-rw-r--r--src/test/ui/issues/issue-77218.rs11
-rw-r--r--src/test/ui/issues/issue-77218.stderr40
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218-2.fixed7
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218-2.rs7
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218-2.stderr16
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218.fixed6
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218.rs6
-rw-r--r--src/test/ui/issues/issue-77218/issue-77218.stderr18
-rw-r--r--src/test/ui/mismatched_types/issue-84976.stderr6
-rw-r--r--src/test/ui/output-type-mismatch.stderr4
-rw-r--r--src/test/ui/static/static-mut-bad-types.stderr4
-rw-r--r--src/test/ui/suggestions/if-let-typo.stderr5
-rw-r--r--src/test/ui/suggestions/mut-ref-reassignment.stderr8
-rw-r--r--src/test/ui/type-alias-impl-trait/argument-types.stderr2
-rw-r--r--src/test/ui/type/type-check/assignment-expected-bool.stderr4
-rw-r--r--src/test/ui/type/type-check/assignment-in-if.stderr4
-rw-r--r--src/test/ui/typeck/issue-81293.stderr3
-rw-r--r--src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr2
39 files changed, 297 insertions, 117 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index a0a63620c08..9c579209fe5 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -915,14 +915,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
             );
         }
         if !self.sess.features_untracked().destructuring_assignment {
-            feature_err(
+            let mut err = feature_err(
                 &self.sess.parse_sess,
                 sym::destructuring_assignment,
                 eq_sign_span,
                 "destructuring assignments are unstable",
-            )
-            .span_label(lhs.span, "cannot assign to this expression")
-            .emit();
+            );
+            err.span_label(lhs.span, "cannot assign to this expression");
+            if self.is_in_loop_condition {
+                err.span_suggestion_verbose(
+                    lhs.span.shrink_to_lo(),
+                    "you might have meant to use pattern destructuring",
+                    "let ".to_string(),
+                    rustc_errors::Applicability::MachineApplicable,
+                );
+            }
+            err.emit();
         }
 
         let mut assignments = vec![];
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 28712e06582..77f7cccc04b 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1458,7 +1458,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             cause,
                             expected,
                             found,
-                            coercion_error,
+                            coercion_error.clone(),
                             fcx,
                             parent_id,
                             expression.map(|expr| (expr, blk_id)),
@@ -1472,7 +1472,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                             cause,
                             expected,
                             found,
-                            coercion_error,
+                            coercion_error.clone(),
                             fcx,
                             id,
                             None,
@@ -1483,7 +1483,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                         }
                     }
                     _ => {
-                        err = fcx.report_mismatched_types(cause, expected, found, coercion_error);
+                        err = fcx.report_mismatched_types(
+                            cause,
+                            expected,
+                            found,
+                            coercion_error.clone(),
+                        );
                     }
                 }
 
@@ -1492,7 +1497,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 }
 
                 if let Some(expr) = expression {
-                    fcx.emit_coerce_suggestions(&mut err, expr, found, expected, None);
+                    fcx.emit_coerce_suggestions(
+                        &mut err,
+                        expr,
+                        found,
+                        expected,
+                        None,
+                        coercion_error,
+                    );
                 }
 
                 err.emit_unless(unsized_return);
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index ece2d7b4f37..5d121913aac 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir::{is_range_literal, Node};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
 use rustc_span::symbol::sym;
@@ -27,8 +28,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+        error: TypeError<'tcx>,
     ) {
-        self.annotate_expected_due_to_let_ty(err, expr);
+        self.annotate_expected_due_to_let_ty(err, expr, error);
         self.suggest_box_deref(err, expr, expected, expr_ty);
         self.suggest_compatible_variants(err, expr, expected, expr_ty);
         self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
@@ -145,9 +147,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let expr = expr.peel_drop_temps();
         let cause = self.misc(expr.span);
         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
-        let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
+        let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e.clone());
 
-        self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr);
+        self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr, e);
 
         (expected, Some(err))
     }
@@ -156,15 +158,80 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         err: &mut DiagnosticBuilder<'_>,
         expr: &hir::Expr<'_>,
+        error: TypeError<'_>,
     ) {
         let parent = self.tcx.hir().get_parent_node(expr.hir_id);
-        if let Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })) =
-            self.tcx.hir().find(parent)
-        {
-            if init.hir_id == expr.hir_id {
+        match (self.tcx.hir().find(parent), error) {
+            (Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })), _)
+                if init.hir_id == expr.hir_id =>
+            {
                 // Point at `let` assignment type.
                 err.span_label(ty.span, "expected due to this");
             }
+            (
+                Some(hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Assign(lhs, rhs, _), ..
+                })),
+                TypeError::Sorts(ExpectedFound { expected, .. }),
+            ) if rhs.hir_id == expr.hir_id && !expected.is_closure() => {
+                // We ignore closures explicitly because we already point at them elsewhere.
+                // Point at the assigned-to binding.
+                let mut primary_span = lhs.span;
+                let mut secondary_span = lhs.span;
+                let mut post_message = "";
+                if let hir::ExprKind::Path(hir::QPath::Resolved(
+                    None,
+                    hir::Path { res: hir::def::Res::Local(hir_id), .. },
+                )) = lhs.kind
+                {
+                    if let Some(hir::Node::Binding(pat)) = self.tcx.hir().find(*hir_id) {
+                        let parent = self.tcx.hir().get_parent_node(pat.hir_id);
+                        primary_span = pat.span;
+                        secondary_span = pat.span;
+                        match self.tcx.hir().find(parent) {
+                            Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
+                                primary_span = ty.span;
+                                post_message = " type";
+                            }
+                            Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => {
+                                primary_span = init.span;
+                                post_message = " value";
+                            }
+                            Some(hir::Node::Param(hir::Param { ty_span, .. })) => {
+                                primary_span = *ty_span;
+                                post_message = " parameter type";
+                            }
+                            _ => {}
+                        }
+                    }
+                }
+
+                if primary_span != secondary_span
+                    && self
+                        .tcx
+                        .sess
+                        .source_map()
+                        .is_multiline(secondary_span.shrink_to_hi().until(primary_span))
+                {
+                    // We are pointing at the binding's type or initializer value, but it's pattern
+                    // is in a different line, so we point at both.
+                    err.span_label(secondary_span, "expected due to the type of this binding");
+                    err.span_label(primary_span, &format!("expected due to this{}", post_message));
+                } else if post_message == "" {
+                    // We are pointing at either the assignment lhs or the binding def pattern.
+                    err.span_label(primary_span, "expected due to the type of this binding");
+                } else {
+                    // We are pointing at the binding's type or initializer value.
+                    err.span_label(primary_span, &format!("expected due to this{}", post_message));
+                }
+
+                if !lhs.is_syntactic_place_expr() {
+                    // We already emitted E0070 "invalid left-hand side of assignment", so we
+                    // silence this.
+                    err.delay_as_bug();
+                }
+            }
+            _ => {}
         }
     }
 
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index c9fa0fd72fc..eb997b014c7 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -833,7 +833,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         lhs: &'tcx hir::Expr<'tcx>,
         err_code: &'static str,
-        expr_span: &Span,
+        op_span: Span,
     ) {
         if lhs.is_syntactic_place_expr() {
             return;
@@ -841,11 +841,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
         let mut err = self.tcx.sess.struct_span_err_with_code(
-            *expr_span,
+            op_span,
             "invalid left-hand side of assignment",
             DiagnosticId::Error(err_code.into()),
         );
         err.span_label(lhs.span, "cannot assign to this expression");
+
+        let mut parent = self.tcx.hir().get_parent_node(lhs.hir_id);
+        while let Some(node) = self.tcx.hir().find(parent) {
+            match node {
+                hir::Node::Expr(hir::Expr {
+                    kind:
+                        hir::ExprKind::Loop(
+                            hir::Block {
+                                expr:
+                                    Some(hir::Expr {
+                                        kind:
+                                            hir::ExprKind::Match(expr, ..) | hir::ExprKind::If(expr, ..),
+                                        ..
+                                    }),
+                                ..
+                            },
+                            _,
+                            hir::LoopSource::While,
+                            _,
+                        ),
+                    ..
+                }) => {
+                    // We have a situation like `while Some(0) = value.get(0) {`, where `while let`
+                    // was more likely intended.
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_lo(),
+                        "you might have meant to use pattern destructuring",
+                        "let ".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                    if !self.sess().features_untracked().destructuring_assignment {
+                        // We already emit an E0658 with a suggestion for `while let`, this is
+                        // redundant output.
+                        err.delay_as_bug();
+                    }
+                    break;
+                }
+                hir::Node::Item(_)
+                | hir::Node::ImplItem(_)
+                | hir::Node::TraitItem(_)
+                | hir::Node::Crate(_) => break,
+                _ => {
+                    parent = self.tcx.hir().get_parent_node(parent);
+                }
+            }
+        }
+
         err.emit();
     }
 
@@ -953,7 +1000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 (Applicability::MaybeIncorrect, false)
             };
-            if !lhs.is_syntactic_place_expr() {
+            if !lhs.is_syntactic_place_expr() && !matches!(lhs.kind, hir::ExprKind::Lit(_)) {
                 // Do not suggest `if let x = y` as `==` is way more likely to be the intention.
                 let hir = self.tcx.hir();
                 if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
@@ -965,7 +1012,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         "let ".to_string(),
                         applicability,
                     );
-                }
+                };
             }
             if eq {
                 err.span_suggestion_verbose(
@@ -986,7 +1033,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return self.tcx.ty_error();
         }
 
-        self.check_lhs_assignable(lhs, "E0070", span);
+        self.check_lhs_assignable(lhs, "E0070", *span);
 
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
         let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs));
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index a119a6838b8..74d7f0a80b6 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -737,6 +737,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         &mut |err| {
                             if let Some(expected_ty) = expected.only_has_type(self) {
                                 self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
+                                if expected_ty == self.tcx.types.bool {
+                                    // If this is caused by a missing `let` in a `while let`,
+                                    // silence this redundant error, as we already emit E0070.
+                                    let parent = self.tcx.hir().get_parent_node(blk.hir_id);
+                                    let parent = self.tcx.hir().get_parent_node(parent);
+                                    let parent = self.tcx.hir().get_parent_node(parent);
+                                    let parent = self.tcx.hir().get_parent_node(parent);
+                                    let parent = self.tcx.hir().get_parent_node(parent);
+                                    match self.tcx.hir().find(parent) {
+                                        Some(hir::Node::Expr(hir::Expr {
+                                            kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _),
+                                            ..
+                                        })) => {
+                                            err.delay_as_bug();
+                                        }
+                                        _ => {}
+                                    }
+                                }
                             }
                             if let Some(fn_span) = fn_span {
                                 err.span_label(
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 9c53a1d4eb6..f83209f57a8 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -42,7 +42,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return_ty
             };
 
-        self.check_lhs_assignable(lhs, "E0067", &op.span);
+        self.check_lhs_assignable(lhs, "E0067", op.span);
 
         ty
     }
diff --git a/src/test/ui/dst/dst-bad-assign-3.stderr b/src/test/ui/dst/dst-bad-assign-3.stderr
index 04e46233532..b326dbbbc14 100644
--- a/src/test/ui/dst/dst-bad-assign-3.stderr
+++ b/src/test/ui/dst/dst-bad-assign-3.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/dst-bad-assign-3.rs:33:12
    |
 LL |     f5.2 = Bar1 {f: 36};
-   |            ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+   |     ----   ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+   |     |
+   |     expected due to the type of this binding
    |
    = note: expected trait object `dyn ToBar`
                     found struct `Bar1`
diff --git a/src/test/ui/dst/dst-bad-assign.stderr b/src/test/ui/dst/dst-bad-assign.stderr
index f87a34c6d37..614f2138751 100644
--- a/src/test/ui/dst/dst-bad-assign.stderr
+++ b/src/test/ui/dst/dst-bad-assign.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/dst-bad-assign.rs:35:14
    |
 LL |     f5.ptr = Bar1 {f: 36};
-   |              ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+   |     ------   ^^^^^^^^^^^^ expected trait object `dyn ToBar`, found struct `Bar1`
+   |     |
+   |     expected due to the type of this binding
    |
    = note: expected trait object `dyn ToBar`
                     found struct `Bar1`
diff --git a/src/test/ui/error-codes/E0070.rs b/src/test/ui/error-codes/E0070.rs
index ab956d81098..3aae0c9ff6e 100644
--- a/src/test/ui/error-codes/E0070.rs
+++ b/src/test/ui/error-codes/E0070.rs
@@ -6,7 +6,6 @@ fn some_function() {
     SOME_CONST = 14; //~ ERROR E0070
     1 = 3; //~ ERROR E0070
     some_other_func() = 4; //~ ERROR E0070
-                           //~^ ERROR E0308
 }
 
 fn main() {
diff --git a/src/test/ui/error-codes/E0070.stderr b/src/test/ui/error-codes/E0070.stderr
index e24d498e352..8868bc257a7 100644
--- a/src/test/ui/error-codes/E0070.stderr
+++ b/src/test/ui/error-codes/E0070.stderr
@@ -22,13 +22,6 @@ LL |     some_other_func() = 4;
    |     |
    |     cannot assign to this expression
 
-error[E0308]: mismatched types
-  --> $DIR/E0070.rs:8:25
-   |
-LL |     some_other_func() = 4;
-   |                         ^ expected `()`, found integer
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0070, E0308.
-For more information about an error, try `rustc --explain E0070`.
+For more information about this error, try `rustc --explain E0070`.
diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs
index 1c6b9805b51..229c174daa8 100644
--- a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs
+++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs
@@ -1,10 +1,10 @@
 // Test that we use fully-qualified type names in error messages.
 
 fn main() {
-    let x: Option<usize>;
+    let x: //~ NOTE expected due to the type of this binding
+        Option<usize>; //~ NOTE expected due to this type
     x = 5;
     //~^ ERROR mismatched types
-    //~| expected enum `Option<usize>`
-    //~| found type `{integer}`
-    //~| expected enum `Option`, found integer
+    //~| NOTE expected enum `Option<usize>`
+    //~| NOTE expected enum `Option`, found integer
 }
diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr
index 03fb299b39c..4750c5ccdf7 100644
--- a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr
+++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr
@@ -1,6 +1,10 @@
 error[E0308]: mismatched types
-  --> $DIR/fully-qualified-type-name1.rs:5:9
+  --> $DIR/fully-qualified-type-name1.rs:6:9
    |
+LL |     let x:
+   |         - expected due to the type of this binding
+LL |         Option<usize>;
+   |         ------------- expected due to this type
 LL |     x = 5;
    |         ^ expected enum `Option`, found integer
    |
diff --git a/src/test/ui/impl-trait/impl-trait-in-macro.stderr b/src/test/ui/impl-trait/impl-trait-in-macro.stderr
index b5f9986ce40..7cfbe3447b8 100644
--- a/src/test/ui/impl-trait/impl-trait-in-macro.stderr
+++ b/src/test/ui/impl-trait/impl-trait-in-macro.stderr
@@ -7,6 +7,8 @@ LL |     ($($tr:tt)*) => { impl $($tr)* };
    |                       expected type parameter
    |                       found type parameter
 ...
+LL |     let mut a = x;
+   |                 - expected due to this value
 LL |     a = y;
    |         ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
    |
diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.stderr b/src/test/ui/impl-trait/universal-two-impl-traits.stderr
index 7c120235fd1..ab8a53d0db3 100644
--- a/src/test/ui/impl-trait/universal-two-impl-traits.stderr
+++ b/src/test/ui/impl-trait/universal-two-impl-traits.stderr
@@ -6,6 +6,7 @@ LL | fn foo(x: impl Debug, y: impl Debug) -> String {
    |           |
    |           expected type parameter
 LL |     let mut a = x;
+   |                 - expected due to this value
 LL |     a = y;
    |         ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug`
    |
diff --git a/src/test/ui/integral-variable-unification-error.rs b/src/test/ui/integral-variable-unification-error.rs
index 5200b4a829d..8d1621321e8 100644
--- a/src/test/ui/integral-variable-unification-error.rs
+++ b/src/test/ui/integral-variable-unification-error.rs
@@ -1,6 +1,8 @@
 fn main() {
-    let mut x = 2;
+    let mut x //~ NOTE expected due to the type of this binding
+        =
+        2; //~ NOTE expected due to this value
     x = 5.0;
     //~^ ERROR mismatched types
-    //~| expected integer, found floating-point number
+    //~| NOTE expected integer, found floating-point number
 }
diff --git a/src/test/ui/integral-variable-unification-error.stderr b/src/test/ui/integral-variable-unification-error.stderr
index b49bff1b0d8..f77c265a2ad 100644
--- a/src/test/ui/integral-variable-unification-error.stderr
+++ b/src/test/ui/integral-variable-unification-error.stderr
@@ -1,6 +1,11 @@
 error[E0308]: mismatched types
-  --> $DIR/integral-variable-unification-error.rs:3:9
+  --> $DIR/integral-variable-unification-error.rs:5:9
    |
+LL |     let mut x
+   |         ----- expected due to the type of this binding
+LL |         =
+LL |         2;
+   |         - expected due to this value
 LL |     x = 5.0;
    |         ^^^ expected integer, found floating-point number
 
diff --git a/src/test/ui/issues/issue-13407.rs b/src/test/ui/issues/issue-13407.rs
index fa53d55f5b3..7ea81ffb59e 100644
--- a/src/test/ui/issues/issue-13407.rs
+++ b/src/test/ui/issues/issue-13407.rs
@@ -5,6 +5,5 @@ mod A {
 fn main() {
     A::C = 1;
     //~^ ERROR: invalid left-hand side of assignment
-    //~| ERROR: mismatched types
     //~| ERROR: struct `C` is private
 }
diff --git a/src/test/ui/issues/issue-13407.stderr b/src/test/ui/issues/issue-13407.stderr
index 4df1813a710..54b6c640d9d 100644
--- a/src/test/ui/issues/issue-13407.stderr
+++ b/src/test/ui/issues/issue-13407.stderr
@@ -18,13 +18,7 @@ LL |     A::C = 1;
    |     |
    |     cannot assign to this expression
 
-error[E0308]: mismatched types
-  --> $DIR/issue-13407.rs:6:12
-   |
-LL |     A::C = 1;
-   |            ^ expected struct `C`, found integer
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0070, E0308, E0603.
+Some errors have detailed explanations: E0070, E0603.
 For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/issues/issue-2951.stderr b/src/test/ui/issues/issue-2951.stderr
index b966b339389..538bbe2f502 100644
--- a/src/test/ui/issues/issue-2951.stderr
+++ b/src/test/ui/issues/issue-2951.stderr
@@ -6,6 +6,7 @@ LL | fn foo<T, U>(x: T, y: U) {
    |        |
    |        expected type parameter
 LL |     let mut xx = x;
+   |                  - expected due to this value
 LL |     xx = y;
    |          ^ expected type parameter `T`, found type parameter `U`
    |
diff --git a/src/test/ui/issues/issue-53348.rs b/src/test/ui/issues/issue-53348.rs
index 65f4656b022..d2f8c77c0ce 100644
--- a/src/test/ui/issues/issue-53348.rs
+++ b/src/test/ui/issues/issue-53348.rs
@@ -5,7 +5,7 @@ fn main() {
 
     v.into_iter().map(|s|s.to_owned()).collect::<Vec<_>>();
 
-    let mut a = String::new();
+    let mut a = String::new(); //~ NOTE expected due to this value
     for i in v {
         a = *i.to_string();
         //~^ ERROR mismatched types
diff --git a/src/test/ui/issues/issue-53348.stderr b/src/test/ui/issues/issue-53348.stderr
index 8f500261243..71d9f5b3dbb 100644
--- a/src/test/ui/issues/issue-53348.stderr
+++ b/src/test/ui/issues/issue-53348.stderr
@@ -1,6 +1,9 @@
 error[E0308]: mismatched types
   --> $DIR/issue-53348.rs:10:13
    |
+LL |     let mut a = String::new();
+   |                 ------------- expected due to this value
+LL |     for i in v {
 LL |         a = *i.to_string();
    |             ^^^^^^^^^^^^^^ expected struct `String`, found `str`
 
diff --git a/src/test/ui/issues/issue-77218.rs b/src/test/ui/issues/issue-77218.rs
deleted file mode 100644
index a6a2401795f..00000000000
--- a/src/test/ui/issues/issue-77218.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-fn main() {
-    let value = [7u8];
-    while Some(0) = value.get(0) { //~ ERROR destructuring assignments are unstable
-        //~| ERROR invalid left-hand side of assignment
-        //~| ERROR mismatched types
-        //~| ERROR mismatched types
-
-        // FIXME The following diagnostic should also be emitted
-        // HELP you might have meant to use pattern matching
-    }
-}
diff --git a/src/test/ui/issues/issue-77218.stderr b/src/test/ui/issues/issue-77218.stderr
deleted file mode 100644
index ce70c0111be..00000000000
--- a/src/test/ui/issues/issue-77218.stderr
+++ /dev/null
@@ -1,40 +0,0 @@
-error[E0658]: destructuring assignments are unstable
-  --> $DIR/issue-77218.rs:3:19
-   |
-LL |     while Some(0) = value.get(0) {
-   |           ------- ^
-   |           |
-   |           cannot assign to this expression
-   |
-   = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
-   = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
-
-error[E0070]: invalid left-hand side of assignment
-  --> $DIR/issue-77218.rs:3:19
-   |
-LL |     while Some(0) = value.get(0) {
-   |                -  ^
-   |                |
-   |                cannot assign to this expression
-
-error[E0308]: mismatched types
-  --> $DIR/issue-77218.rs:3:16
-   |
-LL |     while Some(0) = value.get(0) {
-   |                ^ expected integer, found `&u8`
-   |
-help: consider dereferencing the borrow
-   |
-LL |     while Some(*0) = value.get(0) {
-   |                +
-
-error[E0308]: mismatched types
-  --> $DIR/issue-77218.rs:3:11
-   |
-LL |     while Some(0) = value.get(0) {
-   |           ^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0070, E0308, E0658.
-For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/issues/issue-77218/issue-77218-2.fixed b/src/test/ui/issues/issue-77218/issue-77218-2.fixed
new file mode 100644
index 00000000000..06487fe0886
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218-2.fixed
@@ -0,0 +1,7 @@
+// run-rustfix
+#![feature(destructuring_assignment)]
+fn main() {
+    let value = [7u8];
+    while let Some(0) = value.get(0) { //~ ERROR invalid left-hand side of assignment
+    }
+}
diff --git a/src/test/ui/issues/issue-77218/issue-77218-2.rs b/src/test/ui/issues/issue-77218/issue-77218-2.rs
new file mode 100644
index 00000000000..e19cec08e43
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218-2.rs
@@ -0,0 +1,7 @@
+// run-rustfix
+#![feature(destructuring_assignment)]
+fn main() {
+    let value = [7u8];
+    while Some(0) = value.get(0) { //~ ERROR invalid left-hand side of assignment
+    }
+}
diff --git a/src/test/ui/issues/issue-77218/issue-77218-2.stderr b/src/test/ui/issues/issue-77218/issue-77218-2.stderr
new file mode 100644
index 00000000000..8d9eb2219d5
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218-2.stderr
@@ -0,0 +1,16 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/issue-77218-2.rs:5:19
+   |
+LL |     while Some(0) = value.get(0) {
+   |                -  ^
+   |                |
+   |                cannot assign to this expression
+   |
+help: you might have meant to use pattern destructuring
+   |
+LL |     while let Some(0) = value.get(0) {
+   |           +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
diff --git a/src/test/ui/issues/issue-77218/issue-77218.fixed b/src/test/ui/issues/issue-77218/issue-77218.fixed
new file mode 100644
index 00000000000..4ea51109022
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218.fixed
@@ -0,0 +1,6 @@
+// run-rustfix
+fn main() {
+    let value = [7u8];
+    while let Some(0) = value.get(0) { //~ ERROR destructuring assignments are unstable
+    }
+}
diff --git a/src/test/ui/issues/issue-77218/issue-77218.rs b/src/test/ui/issues/issue-77218/issue-77218.rs
new file mode 100644
index 00000000000..0f3c12f5635
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218.rs
@@ -0,0 +1,6 @@
+// run-rustfix
+fn main() {
+    let value = [7u8];
+    while Some(0) = value.get(0) { //~ ERROR destructuring assignments are unstable
+    }
+}
diff --git a/src/test/ui/issues/issue-77218/issue-77218.stderr b/src/test/ui/issues/issue-77218/issue-77218.stderr
new file mode 100644
index 00000000000..54f49609a44
--- /dev/null
+++ b/src/test/ui/issues/issue-77218/issue-77218.stderr
@@ -0,0 +1,18 @@
+error[E0658]: destructuring assignments are unstable
+  --> $DIR/issue-77218.rs:4:19
+   |
+LL |     while Some(0) = value.get(0) {
+   |           ------- ^
+   |           |
+   |           cannot assign to this expression
+   |
+   = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+   = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+help: you might have meant to use pattern destructuring
+   |
+LL |     while let Some(0) = value.get(0) {
+   |           +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/mismatched_types/issue-84976.stderr b/src/test/ui/mismatched_types/issue-84976.stderr
index 0c27e172941..f8f2b1f0f57 100644
--- a/src/test/ui/mismatched_types/issue-84976.stderr
+++ b/src/test/ui/mismatched_types/issue-84976.stderr
@@ -7,6 +7,9 @@ LL |     length = { foo(&length) };
 error[E0308]: mismatched types
   --> $DIR/issue-84976.rs:17:14
    |
+LL |     let mut length = 0;
+   |                      - expected due to this value
+...
 LL |     length = foo(&length);
    |              ^^^^^^^^^^^^ expected `u32`, found `i32`
 
@@ -19,6 +22,9 @@ LL |     float_length = { bar(&float_length) };
 error[E0308]: mismatched types
   --> $DIR/issue-84976.rs:23:20
    |
+LL |     let mut float_length = 0.0;
+   |                            --- expected due to this value
+...
 LL |     float_length = bar(&float_length);
    |                    ^^^^^^^^^^^^^^^^^^ expected `f32`, found `f64`
 
diff --git a/src/test/ui/output-type-mismatch.stderr b/src/test/ui/output-type-mismatch.stderr
index 533bd87c9cc..4507a4df621 100644
--- a/src/test/ui/output-type-mismatch.stderr
+++ b/src/test/ui/output-type-mismatch.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/output-type-mismatch.rs:5:31
    |
 LL | fn main() { let i: isize; i = f(); }
-   |                               ^^^ expected `isize`, found `()`
+   |                    -----      ^^^ expected `isize`, found `()`
+   |                    |
+   |                    expected due to this type
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/static/static-mut-bad-types.stderr b/src/test/ui/static/static-mut-bad-types.stderr
index ddd98ff4079..e5a59de6f14 100644
--- a/src/test/ui/static/static-mut-bad-types.stderr
+++ b/src/test/ui/static/static-mut-bad-types.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/static-mut-bad-types.rs:5:13
    |
 LL |         a = true;
-   |             ^^^^ expected `isize`, found `bool`
+   |         -   ^^^^ expected `isize`, found `bool`
+   |         |
+   |         expected due to the type of this binding
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/if-let-typo.stderr b/src/test/ui/suggestions/if-let-typo.stderr
index 7f71cb48581..058f42f2200 100644
--- a/src/test/ui/suggestions/if-let-typo.stderr
+++ b/src/test/ui/suggestions/if-let-typo.stderr
@@ -70,11 +70,6 @@ error[E0308]: mismatched types
    |
 LL |     if 3 = foo {}
    |        ^^^^^^^ expected `bool`, found `()`
-   |
-help: you might have meant to use pattern matching
-   |
-LL |     if let 3 = foo {}
-   |        +++
 
 error[E0070]: invalid left-hand side of assignment
   --> $DIR/if-let-typo.rs:10:16
diff --git a/src/test/ui/suggestions/mut-ref-reassignment.stderr b/src/test/ui/suggestions/mut-ref-reassignment.stderr
index fd5677898e6..3bd98c76307 100644
--- a/src/test/ui/suggestions/mut-ref-reassignment.stderr
+++ b/src/test/ui/suggestions/mut-ref-reassignment.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/mut-ref-reassignment.rs:2:11
    |
+LL | fn suggestion(opt: &mut Option<String>) {
+   |                    ------------------- expected due to this parameter type
 LL |     opt = None;
    |           ^^^^ expected mutable reference, found enum `Option`
    |
@@ -14,6 +16,8 @@ LL |     *opt = None;
 error[E0308]: mismatched types
   --> $DIR/mut-ref-reassignment.rs:6:11
    |
+LL | fn no_suggestion(opt: &mut Result<String, ()>) {
+   |                       ----------------------- expected due to this parameter type
 LL |     opt = None
    |           ^^^^ expected mutable reference, found enum `Option`
    |
@@ -23,6 +27,8 @@ LL |     opt = None
 error[E0308]: mismatched types
   --> $DIR/mut-ref-reassignment.rs:10:11
    |
+LL | fn suggestion2(opt: &mut Option<String>) {
+   |                     ------------------- expected due to this parameter type
 LL |     opt = Some(String::new())
    |           ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `Option`
    |
@@ -36,6 +42,8 @@ LL |     *opt = Some(String::new())
 error[E0308]: mismatched types
   --> $DIR/mut-ref-reassignment.rs:14:11
    |
+LL | fn no_suggestion2(opt: &mut Option<String>) {
+   |                        ------------------- expected due to this parameter type
 LL |     opt = Some(42)
    |           ^^^^^^^^ expected mutable reference, found enum `Option`
    |
diff --git a/src/test/ui/type-alias-impl-trait/argument-types.stderr b/src/test/ui/type-alias-impl-trait/argument-types.stderr
index 1cbf9c95d31..a87e44a048b 100644
--- a/src/test/ui/type-alias-impl-trait/argument-types.stderr
+++ b/src/test/ui/type-alias-impl-trait/argument-types.stderr
@@ -4,6 +4,8 @@ error[E0308]: mismatched types
 LL | type Foo = impl Debug;
    |            ---------- the expected opaque type
 ...
+LL | fn foo1(mut x: Foo) {
+   |                --- expected due to this parameter type
 LL |     x = 22_u32;
    |         ^^^^^^ expected opaque type, found `u32`
    |
diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr
index 862ac65bc24..e2b821f7b05 100644
--- a/src/test/ui/type/type-check/assignment-expected-bool.stderr
+++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr
@@ -48,10 +48,6 @@ error[E0308]: mismatched types
 LL |     if 0 = 0 {}
    |        ^^^^^ expected `bool`, found `()`
    |
-help: you might have meant to use pattern matching
-   |
-LL |     if let 0 = 0 {}
-   |        +++
 help: you might have meant to compare for equality
    |
 LL |     if 0 == 0 {}
diff --git a/src/test/ui/type/type-check/assignment-in-if.stderr b/src/test/ui/type/type-check/assignment-in-if.stderr
index 710be9d6a04..f4ef44e2444 100644
--- a/src/test/ui/type/type-check/assignment-in-if.stderr
+++ b/src/test/ui/type/type-check/assignment-in-if.stderr
@@ -37,10 +37,6 @@ error[E0308]: mismatched types
 LL |     if 3 = x {
    |        ^^^^^ expected `bool`, found `()`
    |
-help: you might have meant to use pattern matching
-   |
-LL |     if let 3 = x {
-   |        +++
 help: you might have meant to compare for equality
    |
 LL |     if 3 == x {
diff --git a/src/test/ui/typeck/issue-81293.stderr b/src/test/ui/typeck/issue-81293.stderr
index 1e6ff3b5f9e..c545a563b0d 100644
--- a/src/test/ui/typeck/issue-81293.stderr
+++ b/src/test/ui/typeck/issue-81293.stderr
@@ -7,6 +7,9 @@ LL |     a = c + b * 5;
 error[E0308]: mismatched types
   --> $DIR/issue-81293.rs:6:9
    |
+LL |     let a: u16;
+   |            --- expected due to this type
+...
 LL |     a = c + b * 5;
    |         ^^^^^^^^^ expected `u16`, found `usize`
 
diff --git a/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr b/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr
index fe10fa733d2..56817ee2ca9 100644
--- a/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr
+++ b/src/test/ui/typeck/issue-87771-ice-assign-assign-to-bool.stderr
@@ -1,6 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/issue-87771-ice-assign-assign-to-bool.rs:3:9
    |
+LL |     let mut a;
+   |         ----- expected due to the type of this binding
 LL |     a = a = true;
    |         ^^^^^^^^ expected `bool`, found `()`