Skip to content

Commit acf257e

Browse files
Point at correct exprs for assert_eq type mismatch
1 parent af54d58 commit acf257e

File tree

3 files changed

+69
-16
lines changed

3 files changed

+69
-16
lines changed

compiler/rustc_hir_typeck/src/demand.rs

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_ast::util::parser::PREC_POSTFIX;
33
use rustc_errors::MultiSpan;
44
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
55
use rustc_hir as hir;
6-
use rustc_hir::def::CtorKind;
6+
use rustc_hir::def::{CtorKind, Res};
77
use rustc_hir::intravisit::Visitor;
88
use rustc_hir::lang_items::LangItem;
99
use rustc_hir::{is_range_literal, Node};
@@ -91,6 +91,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9191
self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
9292
}
9393

94+
/// Really hacky heuristic to remap an `assert_eq!` error to the user
95+
/// expressions provided to the macro.
96+
fn adjust_expr_for_assert_eq_macro(
97+
&self,
98+
found_expr: &mut &'tcx hir::Expr<'tcx>,
99+
expected_expr: &mut Option<&'tcx hir::Expr<'tcx>>,
100+
) {
101+
let Some(expected_expr) = expected_expr else { return; };
102+
103+
if !found_expr.span.eq_ctxt(expected_expr.span) {
104+
return;
105+
}
106+
107+
if !found_expr
108+
.span
109+
.ctxt()
110+
.outer_expn_data()
111+
.macro_def_id
112+
.is_some_and(|def_id| self.tcx.is_diagnostic_item(sym::assert_eq_macro, def_id))
113+
{
114+
return;
115+
}
116+
117+
let hir::ExprKind::Unary(
118+
hir::UnOp::Deref,
119+
hir::Expr { kind: hir::ExprKind::Path(found_path), .. },
120+
) = found_expr.kind else { return; };
121+
let hir::ExprKind::Unary(
122+
hir::UnOp::Deref,
123+
hir::Expr { kind: hir::ExprKind::Path(expected_path), .. },
124+
) = expected_expr.kind else { return; };
125+
126+
for (path, name, idx, var) in [
127+
(expected_path, "left_val", 0, expected_expr),
128+
(found_path, "right_val", 1, found_expr),
129+
] {
130+
if let hir::QPath::Resolved(_, path) = path
131+
&& let [segment] = path.segments
132+
&& segment.ident.name.as_str() == name
133+
&& let Res::Local(hir_id) = path.res
134+
&& let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2)
135+
&& let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind
136+
&& let hir::ExprKind::Tup(exprs) = scrutinee.kind
137+
&& let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind
138+
{
139+
*var = macro_arg;
140+
}
141+
}
142+
}
143+
94144
/// Requires that the two types unify, and prints an error message if
95145
/// they don't.
96146
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
@@ -156,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
156206

157207
pub fn demand_coerce(
158208
&self,
159-
expr: &hir::Expr<'tcx>,
209+
expr: &'tcx hir::Expr<'tcx>,
160210
checked_ty: Ty<'tcx>,
161211
expected: Ty<'tcx>,
162212
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -177,10 +227,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
177227
#[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))]
178228
pub fn demand_coerce_diag(
179229
&self,
180-
expr: &hir::Expr<'tcx>,
230+
mut expr: &'tcx hir::Expr<'tcx>,
181231
checked_ty: Ty<'tcx>,
182232
expected: Ty<'tcx>,
183-
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
233+
mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
184234
allow_two_phase: AllowTwoPhase,
185235
) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>) {
186236
let expected = self.resolve_vars_with_obligations(expected);
@@ -190,6 +240,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
190240
Err(e) => e,
191241
};
192242

243+
self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);
244+
193245
self.set_tainted_by_errors(self.tcx.sess.delay_span_bug(
194246
expr.span,
195247
"`TypeError` when attempting coercion but no error emitted",

tests/ui/inference/deref-suggestion.stderr

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,16 @@ LL | fn foo3(_: u32) {}
8484
| ^^^^ ------
8585

8686
error[E0308]: mismatched types
87-
--> $DIR/deref-suggestion.rs:37:5
87+
--> $DIR/deref-suggestion.rs:37:22
8888
|
8989
LL | assert_eq!(3i32, &3i32);
90-
| ^^^^^^^^^^^^^^^^^^^^^^^
91-
| |
92-
| expected `i32`, found `&i32`
93-
| expected because this is `i32`
90+
| ^^^^^ expected `i32`, found `&i32`
91+
|
92+
help: consider removing the borrow
93+
|
94+
LL - assert_eq!(3i32, &3i32);
95+
LL + assert_eq!(3i32, 3i32);
9496
|
95-
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
9697

9798
error[E0308]: mismatched types
9899
--> $DIR/deref-suggestion.rs:40:17

tests/ui/suggestions/dont-suggest-try_into-in-macros.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error[E0308]: mismatched types
2-
--> $DIR/dont-suggest-try_into-in-macros.rs:2:5
2+
--> $DIR/dont-suggest-try_into-in-macros.rs:2:23
33
|
44
LL | assert_eq!(10u64, 10usize);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
6-
| |
7-
| expected `u64`, found `usize`
8-
| expected because this is `u64`
5+
| ^^^^^^^ expected `u64`, found `usize`
96
|
10-
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
7+
help: change the type of the numeric literal from `usize` to `u64`
8+
|
9+
LL | assert_eq!(10u64, 10u64);
10+
| ~~~
1111

1212
error: aborting due to previous error
1313

0 commit comments

Comments
 (0)