@@ -3,7 +3,7 @@ use rustc_ast::util::parser::PREC_POSTFIX;
3
3
use rustc_errors:: MultiSpan ;
4
4
use rustc_errors:: { Applicability , Diagnostic , DiagnosticBuilder , ErrorGuaranteed } ;
5
5
use rustc_hir as hir;
6
- use rustc_hir:: def:: CtorKind ;
6
+ use rustc_hir:: def:: { CtorKind , Res } ;
7
7
use rustc_hir:: intravisit:: Visitor ;
8
8
use rustc_hir:: lang_items:: LangItem ;
9
9
use rustc_hir:: { is_range_literal, Node } ;
@@ -91,6 +91,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
91
91
self . note_wrong_return_ty_due_to_generic_arg ( err, expr, expr_ty) ;
92
92
}
93
93
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
+
94
144
/// Requires that the two types unify, and prints an error message if
95
145
/// they don't.
96
146
pub fn demand_suptype ( & self , sp : Span , expected : Ty < ' tcx > , actual : Ty < ' tcx > ) {
@@ -156,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
156
206
157
207
pub fn demand_coerce (
158
208
& self ,
159
- expr : & hir:: Expr < ' tcx > ,
209
+ expr : & ' tcx hir:: Expr < ' tcx > ,
160
210
checked_ty : Ty < ' tcx > ,
161
211
expected : Ty < ' tcx > ,
162
212
expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
@@ -177,10 +227,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
177
227
#[ instrument( level = "debug" , skip( self , expr, expected_ty_expr, allow_two_phase) ) ]
178
228
pub fn demand_coerce_diag (
179
229
& self ,
180
- expr : & hir:: Expr < ' tcx > ,
230
+ mut expr : & ' tcx hir:: Expr < ' tcx > ,
181
231
checked_ty : Ty < ' tcx > ,
182
232
expected : Ty < ' tcx > ,
183
- expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
233
+ mut expected_ty_expr : Option < & ' tcx hir:: Expr < ' tcx > > ,
184
234
allow_two_phase : AllowTwoPhase ,
185
235
) -> ( Ty < ' tcx > , Option < DiagnosticBuilder < ' tcx , ErrorGuaranteed > > ) {
186
236
let expected = self . resolve_vars_with_obligations ( expected) ;
@@ -190,6 +240,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
190
240
Err ( e) => e,
191
241
} ;
192
242
243
+ self . adjust_expr_for_assert_eq_macro ( & mut expr, & mut expected_ty_expr) ;
244
+
193
245
self . set_tainted_by_errors ( self . tcx . sess . delay_span_bug (
194
246
expr. span ,
195
247
"`TypeError` when attempting coercion but no error emitted" ,
0 commit comments