@@ -51,10 +51,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
51
51
52
52
fn visit_expr ( & mut self , ex : & ' tcx hir:: Expr < ' tcx > ) {
53
53
intravisit:: walk_expr ( self , ex) ;
54
-
55
- // FIXME(let_chains): Deal with `::Let`.
56
- if let hir:: ExprKind :: Match ( ref scrut , ref arms , source ) = ex . kind {
57
- self . check_match ( scrut , arms , source ) ;
54
+ match & ex . kind {
55
+ hir :: ExprKind :: Match ( scrut , arms , source ) => self . check_match ( scrut , arms , * source ) ,
56
+ hir:: ExprKind :: Let ( pat , scrut ) => self . check_let ( pat , scrut ) ,
57
+ _ => { }
58
58
}
59
59
}
60
60
@@ -145,6 +145,24 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
145
145
MatchCheckCtxt :: create_and_enter ( self . tcx , self . param_env , module, |cx| f ( cx) ) ;
146
146
}
147
147
148
+ fn check_let ( & mut self , pat : & ' tcx hir:: Pat < ' tcx > , scrut : & hir:: Expr < ' _ > ) {
149
+ self . check_patterns ( false , pat) ;
150
+ // FIXME(let_chains, Centril): Exhaustiveness of `let p = e` is unnecessary for soundness.
151
+ // Consider dropping the checks here, at least the non-linting part for perf reasons.
152
+ self . check_in_cx ( scrut. hir_id , |ref mut cx| {
153
+ let mut have_errors = false ;
154
+ let pattern = self . lower_pattern ( cx, pat, & mut have_errors) . 0 ;
155
+ if have_errors {
156
+ return ;
157
+ }
158
+ let wild = cx. pattern_arena . alloc ( super :: Pat :: wildcard_from_ty ( pattern. ty ) ) ;
159
+ wild. span = pattern. span ;
160
+ let arms = & [ ( pattern, pat. hir_id , false ) , ( wild, pat. hir_id , false ) ] ;
161
+ let desugar = hir:: MatchSource :: IfLetDesugar { contains_else_clause : true } ;
162
+ self . check_union_irrefutable ( cx, scrut, arms, desugar)
163
+ } ) ;
164
+ }
165
+
148
166
fn check_match (
149
167
& mut self ,
150
168
scrut : & hir:: Expr < ' _ > ,
@@ -158,36 +176,47 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
158
176
159
177
self . check_in_cx ( scrut. hir_id , |ref mut cx| {
160
178
let mut have_errors = false ;
161
-
162
179
let inlined_arms: Vec < _ > = arms
163
180
. iter ( )
164
181
. map ( |hir:: Arm { pat, guard, .. } | {
165
182
( self . lower_pattern ( cx, pat, & mut have_errors) . 0 , pat. hir_id , guard. is_some ( ) )
166
183
} )
167
184
. collect ( ) ;
168
-
169
- // Bail out early if inlining failed.
170
185
if have_errors {
186
+ // Inlining failed, bail out early.
171
187
return ;
172
188
}
173
189
174
- // Fourth, check for unreachable arms.
175
- let matrix = check_arms ( cx, & inlined_arms, source) ;
176
-
177
- // Fifth, check if the match is exhaustive.
178
- let scrut_ty = self . tables . node_type ( scrut. hir_id ) ;
179
- // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
180
- // since an empty matrix can occur when there are arms, if those arms all have guards.
181
- let is_empty_match = inlined_arms. is_empty ( ) ;
182
- check_exhaustive ( cx, scrut_ty, scrut. span , & matrix, scrut. hir_id , is_empty_match) ;
190
+ self . check_union_irrefutable ( cx, scrut, & inlined_arms, source) ;
183
191
} )
184
192
}
185
193
194
+ fn check_union_irrefutable < ' p > (
195
+ & self ,
196
+ cx : & mut MatchCheckCtxt < ' p , ' tcx > ,
197
+ scrut : & hir:: Expr < ' _ > ,
198
+ arms : & [ ( & ' p super :: Pat < ' tcx > , HirId , bool ) ] ,
199
+ source : hir:: MatchSource ,
200
+ ) {
201
+ // Check for unreachable arms.
202
+ let matrix = check_arms ( cx, & arms, source) ;
203
+
204
+ // Check if the match is exhaustive.
205
+ let scrut_ty = self . tables . node_type ( scrut. hir_id ) ;
206
+ // Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
207
+ // since an empty matrix can occur when there are arms, if those arms all have guards.
208
+ check_exhaustive ( cx, scrut_ty, scrut. span , & matrix, scrut. hir_id , arms. is_empty ( ) ) ;
209
+ }
210
+
186
211
fn check_irrefutable ( & self , pat : & ' tcx Pat < ' tcx > , origin : & str , sp : Option < Span > ) {
187
212
self . check_in_cx ( pat. hir_id , |ref mut cx| {
188
- let ( pattern, pattern_ty) = self . lower_pattern ( cx, pat, & mut false ) ;
189
- let pats: Matrix < ' _ , ' _ > = vec ! [ PatStack :: from_pattern( pattern) ] . into_iter ( ) . collect ( ) ;
213
+ let mut has_errors = false ;
214
+ let ( pattern, pattern_ty) = self . lower_pattern ( cx, pat, & mut has_errors) ;
215
+ if has_errors {
216
+ return ;
217
+ }
190
218
219
+ let pats: Matrix < ' _ , ' _ > = vec ! [ PatStack :: from_pattern( pattern) ] . into_iter ( ) . collect ( ) ;
191
220
let witnesses = match check_not_useful ( cx, pattern_ty, & pats, pat. hir_id ) {
192
221
Ok ( _) => return ,
193
222
Err ( err) => err,
0 commit comments