@@ -3,7 +3,7 @@ use rustc_ast::util::parser::PREC_POSTFIX;
33use rustc_errors:: MultiSpan ;
44use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed } ;
55use rustc_hir as hir;
6- use rustc_hir:: def:: CtorKind ;
6+ use rustc_hir:: def:: { CtorKind , Res } ;
77use rustc_hir:: intravisit:: Visitor ;
88use rustc_hir:: lang_items:: LangItem ;
99use 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" ,
0 commit comments