1
1
use crate :: consts:: { constant_context, constant_simple} ;
2
- use crate :: differing_macro_contexts;
2
+ use crate :: { differing_macro_contexts, snippet_opt } ;
3
3
use rustc_ast:: ast:: InlineAsmTemplatePiece ;
4
4
use rustc_data_structures:: fx:: FxHashMap ;
5
5
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
@@ -9,6 +9,7 @@ use rustc_hir::{
9
9
GenericArg , GenericArgs , Guard , HirId , InlineAsmOperand , Lifetime , LifetimeName , ParamName , Pat , PatKind , Path ,
10
10
PathSegment , QPath , Stmt , StmtKind , Ty , TyKind , TypeBinding ,
11
11
} ;
12
+ use rustc_lexer:: { tokenize, TokenKind } ;
12
13
use rustc_lint:: LateContext ;
13
14
use rustc_middle:: ich:: StableHashingContextProvider ;
14
15
use rustc_middle:: ty:: TypeckResults ;
@@ -110,8 +111,54 @@ impl HirEqInterExpr<'_, '_, '_> {
110
111
111
112
/// Checks whether two blocks are the same.
112
113
fn eq_block ( & mut self , left : & Block < ' _ > , right : & Block < ' _ > ) -> bool {
113
- over ( & left. stmts , & right. stmts , |l, r| self . eq_stmt ( l, r) )
114
- && both ( & left. expr , & right. expr , |l, r| self . eq_expr ( l, r) )
114
+ match ( left. stmts , left. expr , right. stmts , right. expr ) {
115
+ ( [ ] , None , [ ] , None ) => {
116
+ // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro
117
+ // expanded to nothing, or the cfg attribute was used.
118
+ let ( left, right) = match (
119
+ snippet_opt ( self . inner . cx , left. span ) ,
120
+ snippet_opt ( self . inner . cx , right. span ) ,
121
+ ) {
122
+ ( Some ( left) , Some ( right) ) => ( left, right) ,
123
+ _ => return true ,
124
+ } ;
125
+ let mut left_pos = 0 ;
126
+ let left = tokenize ( & left)
127
+ . map ( |t| {
128
+ let end = left_pos + t. len ;
129
+ let s = & left[ left_pos..end] ;
130
+ left_pos = end;
131
+ ( t, s)
132
+ } )
133
+ . filter ( |( t, _) | {
134
+ !matches ! (
135
+ t. kind,
136
+ TokenKind :: LineComment { .. } | TokenKind :: BlockComment { .. } | TokenKind :: Whitespace
137
+ )
138
+ } )
139
+ . map ( |( _, s) | s) ;
140
+ let mut right_pos = 0 ;
141
+ let right = tokenize ( & right)
142
+ . map ( |t| {
143
+ let end = right_pos + t. len ;
144
+ let s = & right[ right_pos..end] ;
145
+ right_pos = end;
146
+ ( t, s)
147
+ } )
148
+ . filter ( |( t, _) | {
149
+ !matches ! (
150
+ t. kind,
151
+ TokenKind :: LineComment { .. } | TokenKind :: BlockComment { .. } | TokenKind :: Whitespace
152
+ )
153
+ } )
154
+ . map ( |( _, s) | s) ;
155
+ left. eq ( right)
156
+ } ,
157
+ _ => {
158
+ over ( & left. stmts , & right. stmts , |l, r| self . eq_stmt ( l, r) )
159
+ && both ( & left. expr , & right. expr , |l, r| self . eq_expr ( l, r) )
160
+ } ,
161
+ }
115
162
}
116
163
117
164
#[ allow( clippy:: similar_names) ]
@@ -131,7 +178,10 @@ impl HirEqInterExpr<'_, '_, '_> {
131
178
}
132
179
}
133
180
134
- let is_eq = match ( & reduce_exprkind ( & left. kind ) , & reduce_exprkind ( & right. kind ) ) {
181
+ let is_eq = match (
182
+ & reduce_exprkind ( self . inner . cx , & left. kind ) ,
183
+ & reduce_exprkind ( self . inner . cx , & right. kind ) ,
184
+ ) {
135
185
( & ExprKind :: AddrOf ( lb, l_mut, ref le) , & ExprKind :: AddrOf ( rb, r_mut, ref re) ) => {
136
186
lb == rb && l_mut == r_mut && self . eq_expr ( le, re)
137
187
} ,
@@ -360,11 +410,30 @@ impl HirEqInterExpr<'_, '_, '_> {
360
410
}
361
411
362
412
/// Some simple reductions like `{ return }` => `return`
363
- fn reduce_exprkind < ' hir > ( kind : & ' hir ExprKind < ' hir > ) -> & ExprKind < ' hir > {
413
+ fn reduce_exprkind < ' hir > ( cx : & LateContext < ' _ > , kind : & ' hir ExprKind < ' hir > ) -> & ' hir ExprKind < ' hir > {
364
414
if let ExprKind :: Block ( block, _) = kind {
365
415
match ( block. stmts , block. expr ) {
416
+ // From an `if let` expression without an `else` block. The arm for the implicit wild pattern is an empty
417
+ // block with an empty span.
418
+ ( [ ] , None ) if block. span . is_empty ( ) => & ExprKind :: Tup ( & [ ] ) ,
366
419
// `{}` => `()`
367
- ( [ ] , None ) => & ExprKind :: Tup ( & [ ] ) ,
420
+ ( [ ] , None ) => match snippet_opt ( cx, block. span ) {
421
+ // Don't reduce if there are any tokens contained in the braces
422
+ Some ( snip)
423
+ if tokenize ( & snip)
424
+ . map ( |t| t. kind )
425
+ . filter ( |t| {
426
+ !matches ! (
427
+ t,
428
+ TokenKind :: LineComment { .. } | TokenKind :: BlockComment { .. } | TokenKind :: Whitespace
429
+ )
430
+ } )
431
+ . ne ( [ TokenKind :: OpenBrace , TokenKind :: CloseBrace ] . iter ( ) . cloned ( ) ) =>
432
+ {
433
+ kind
434
+ } ,
435
+ _ => & ExprKind :: Tup ( & [ ] ) ,
436
+ } ,
368
437
( [ ] , Some ( expr) ) => match expr. kind {
369
438
// `{ return .. }` => `return ..`
370
439
ExprKind :: Ret ( ..) => & expr. kind ,
0 commit comments