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_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 @@ pub fn emit_coerce_suggestions( 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 @@ pub fn demand_eqtype_with_origin( 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 @@ pub fn demand_coerce( #[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>) { let expected = self.resolve_vars_with_obligations(expected); @@ -190,6 +240,8 @@ pub fn demand_coerce_diag( 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