about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs60
-rw-r--r--tests/ui/inference/deref-suggestion.stderr13
-rw-r--r--tests/ui/suggestions/dont-suggest-try_into-in-macros.stderr12
3 files changed, 69 insertions, 16 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index b50630e636b..b62f689ec6b 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -3,7 +3,7 @@ use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::MultiSpan;
 use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
-use rustc_hir::def::CtorKind;
+use rustc_hir::def::{CtorKind, Res};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{is_range_literal, Node};
@@ -91,6 +91,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
     }
 
+    /// Really hacky heuristic to remap an `assert_eq!` error to the user
+    /// expressions provided to the macro.
+    fn adjust_expr_for_assert_eq_macro(
+        &self,
+        found_expr: &mut &'tcx hir::Expr<'tcx>,
+        expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>,
+    ) {
+        let Some(expected_expr) = expected_expr else { return; };
+
+        if !found_expr.span.eq_ctxt(expected_expr.span) {
+            return;
+        }
+
+        if !found_expr
+            .span
+            .ctxt()
+            .outer_expn_data()
+            .macro_def_id
+            .is_some_and(|def_id| self.tcx.is_diagnostic_item(sym::assert_eq_macro, def_id))
+        {
+            return;
+        }
+
+        let hir::ExprKind::Unary(
+            hir::UnOp::Deref,
+            hir::Expr { kind: hir::ExprKind::Path(found_path), .. },
+        ) = found_expr.kind else { return; };
+        let hir::ExprKind::Unary(
+            hir::UnOp::Deref,
+            hir::Expr { kind: hir::ExprKind::Path(expected_path), .. },
+        ) = expected_expr.kind else { return; };
+
+        for (path, name, idx, var) in [
+            (expected_path, "left_val", 0, expected_expr),
+            (found_path, "right_val", 1, found_expr),
+        ] {
+            if let hir::QPath::Resolved(_, path) = path
+                && let [segment] = path.segments
+                && segment.ident.name.as_str() == name
+                && let Res::Local(hir_id) = path.res
+                && let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2)
+                && let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
+                && let hir::ExprKind::Tup(exprs) = scrutinee.kind
+                && let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
+            {
+                *var = macro_arg;
+            }
+        }
+    }
+
     /// Requires that the two types unify, and prints an error message if
     /// they don't.
     pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
@@ -156,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub fn demand_coerce(
         &self,
-        expr: &hir::Expr<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -177,10 +227,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
     pub fn demand_coerce_diag(
         &self,
-        expr: &hir::Expr<'tcx>,
+        mut expr: &'tcx hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
-        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+        mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
         allow_two_phase: AllowTwoPhase,
     ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
         let expected = self.resolve_vars_with_obligations(expected);
@@ -190,6 +240,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Err(e) => e,
         };
 
+        self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);
+
         self.set_tainted_by_errors(self.tcx.sess.delay_span_bug(
             expr.span,
             "`TypeError` when attempting coercion but no error emitted",
diff --git a/tests/ui/inference/deref-suggestion.stderr b/tests/ui/inference/deref-suggestion.stderr
index c58aab42269..096989db0b4 100644
--- a/tests/ui/inference/deref-suggestion.stderr
+++ b/tests/ui/inference/deref-suggestion.stderr
@@ -84,15 +84,16 @@ LL | fn foo3(_: u32) {}
    |    ^^^^ ------
 
 error[E0308]: mismatched types
-  --> $DIR/deref-suggestion.rs:37:5
+  --> $DIR/deref-suggestion.rs:37:22
    |
 LL |     assert_eq!(3i32, &3i32);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
-   |     |
-   |     expected `i32`, found `&i32`
-   |     expected because this is `i32`
+   |                      ^^^^^ expected `i32`, found `&i32`
+   |
+help: consider removing the borrow
+   |
+LL -     assert_eq!(3i32, &3i32);
+LL +     assert_eq!(3i32, 3i32);
    |
-   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0308]: mismatched types
   --> $DIR/deref-suggestion.rs:40:17
diff --git a/tests/ui/suggestions/dont-suggest-try_into-in-macros.stderr b/tests/ui/suggestions/dont-suggest-try_into-in-macros.stderr
index bc6342004f4..319d866003b 100644
--- a/tests/ui/suggestions/dont-suggest-try_into-in-macros.stderr
+++ b/tests/ui/suggestions/dont-suggest-try_into-in-macros.stderr
@@ -1,13 +1,13 @@
 error[E0308]: mismatched types
-  --> $DIR/dont-suggest-try_into-in-macros.rs:2:5
+  --> $DIR/dont-suggest-try_into-in-macros.rs:2:23
    |
 LL |     assert_eq!(10u64, 10usize);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |     |
-   |     expected `u64`, found `usize`
-   |     expected because this is `u64`
+   |                       ^^^^^^^ expected `u64`, found `usize`
    |
-   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: change the type of the numeric literal from `usize` to `u64`
+   |
+LL |     assert_eq!(10u64, 10u64);
+   |                         ~~~
 
 error: aborting due to previous error