@@ -23,7 +23,7 @@ use std::gc::{Gc, GC};
23
23
use std:: iter:: AdditiveIterator ;
24
24
use std:: iter:: range_inclusive;
25
25
use syntax:: ast:: * ;
26
- use syntax:: ast_util:: { is_unguarded , walk_pat} ;
26
+ use syntax:: ast_util:: walk_pat;
27
27
use syntax:: codemap:: { Span , Spanned , DUMMY_SP } ;
28
28
use syntax:: fold:: { Folder , noop_fold_pat} ;
29
29
use syntax:: print:: pprust:: pat_to_string;
@@ -159,13 +159,31 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
159
159
}
160
160
}
161
161
162
- // Third, check for unreachable arms.
163
- check_arms ( cx, arms. as_slice ( ) ) ;
162
+ let mut static_inliner = StaticInliner :: new ( cx. tcx ) ;
163
+ let inlined_arms = arms
164
+ . iter ( )
165
+ . map ( |arm| Arm {
166
+ pats : arm. pats . iter ( ) . map ( |pat| {
167
+ static_inliner. fold_pat ( * pat)
168
+ } ) . collect ( ) ,
169
+ ..arm. clone ( )
170
+ } )
171
+ . collect :: < Vec < Arm > > ( ) ;
172
+
173
+ if static_inliner. failed {
174
+ return ;
175
+ }
176
+
177
+ // Third, check if there are any references to NaN that we should warn about.
178
+ check_for_static_nan ( cx, inlined_arms. as_slice ( ) ) ;
179
+
180
+ // Fourth, check for unreachable arms.
181
+ check_arms ( cx, inlined_arms. as_slice ( ) ) ;
164
182
165
183
// Finally, check if the whole match expression is exhaustive.
166
184
// Check for empty enum, because is_useful only works on inhabited types.
167
185
let pat_ty = node_id_to_type ( cx. tcx , scrut. id ) ;
168
- if arms . is_empty ( ) {
186
+ if inlined_arms . is_empty ( ) {
169
187
if !type_is_empty ( cx. tcx , pat_ty) {
170
188
// We know the type is inhabited, so this must be wrong
171
189
span_err ! ( cx. tcx. sess, ex. span, E0002 ,
@@ -177,19 +195,16 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
177
195
return ;
178
196
}
179
197
180
- let mut static_inliner = StaticInliner { tcx : cx. tcx } ;
181
- let matrix: Matrix = arms
182
- . iter ( )
183
- . filter ( |& arm| is_unguarded ( arm) )
184
- . flat_map ( |arm| arm. pats . iter ( ) )
185
- . map ( |pat| vec ! [ static_inliner. fold_pat( * pat) ] )
198
+ let matrix: Matrix = inlined_arms
199
+ . move_iter ( )
200
+ . filter ( |arm| arm. guard . is_none ( ) )
201
+ . flat_map ( |arm| arm. pats . move_iter ( ) )
202
+ . map ( |pat| vec ! [ pat] )
186
203
. collect ( ) ;
187
204
check_exhaustive ( cx, ex. span , & matrix) ;
188
205
} ,
189
206
ExprForLoop ( ref pat, _, _, _) => {
190
- let mut static_inliner = StaticInliner {
191
- tcx : cx. tcx
192
- } ;
207
+ let mut static_inliner = StaticInliner :: new ( cx. tcx ) ;
193
208
match is_refutable ( cx, static_inliner. fold_pat ( * pat) ) {
194
209
Some ( uncovered_pat) => {
195
210
cx. tcx . sess . span_err (
@@ -216,28 +231,31 @@ fn is_expr_const_nan(tcx: &ty::ctxt, expr: &Expr) -> bool {
216
231
}
217
232
}
218
233
219
- // Check for unreachable patterns
220
- fn check_arms ( cx : & MatchCheckCtxt , arms : & [ Arm ] ) {
221
- let mut seen = Matrix ( vec ! ( ) ) ;
222
- let mut static_inliner = StaticInliner { tcx : cx. tcx } ;
234
+ // Check that we do not match against a static NaN (#6804)
235
+ fn check_for_static_nan ( cx : & MatchCheckCtxt , arms : & [ Arm ] ) {
223
236
for arm in arms. iter ( ) {
224
- for pat in arm. pats . iter ( ) {
225
- let inlined = static_inliner. fold_pat ( * pat) ;
226
-
227
- // Check that we do not match against a static NaN (#6804)
228
- walk_pat ( & * inlined, |p| {
237
+ for & pat in arm. pats . iter ( ) {
238
+ walk_pat ( & * pat, |p| {
229
239
match p. node {
230
240
PatLit ( expr) if is_expr_const_nan ( cx. tcx , & * expr) => {
231
- span_warn ! ( cx. tcx. sess, pat . span, E0003 ,
241
+ span_warn ! ( cx. tcx. sess, p . span, E0003 ,
232
242
"unmatchable NaN in pattern, \
233
243
use the is_nan method in a guard instead") ;
234
244
}
235
245
_ => ( )
236
246
}
237
247
true
238
248
} ) ;
249
+ }
250
+ }
251
+ }
239
252
240
- let v = vec ! [ inlined] ;
253
+ // Check for unreachable patterns
254
+ fn check_arms ( cx : & MatchCheckCtxt , arms : & [ Arm ] ) {
255
+ let mut seen = Matrix ( vec ! ( ) ) ;
256
+ for arm in arms. iter ( ) {
257
+ for & pat in arm. pats . iter ( ) {
258
+ let v = vec ! [ pat] ;
241
259
match is_useful ( cx, & seen, v. as_slice ( ) , LeaveOutWitness ) {
242
260
NotUseful => span_err ! ( cx. tcx. sess, pat. span, E0001 , "unreachable pattern" ) ,
243
261
Useful => ( ) ,
@@ -293,7 +311,17 @@ fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
293
311
}
294
312
295
313
pub struct StaticInliner < ' a > {
296
- pub tcx : & ' a ty:: ctxt
314
+ pub tcx : & ' a ty:: ctxt ,
315
+ pub failed : bool
316
+ }
317
+
318
+ impl < ' a > StaticInliner < ' a > {
319
+ pub fn new < ' a > ( tcx : & ' a ty:: ctxt ) -> StaticInliner < ' a > {
320
+ StaticInliner {
321
+ tcx : tcx,
322
+ failed : false
323
+ }
324
+ }
297
325
}
298
326
299
327
impl < ' a > Folder for StaticInliner < ' a > {
@@ -302,9 +330,17 @@ impl<'a> Folder for StaticInliner<'a> {
302
330
PatIdent ( ..) | PatEnum ( ..) => {
303
331
let def = self . tcx . def_map . borrow ( ) . find_copy ( & pat. id ) ;
304
332
match def {
305
- Some ( DefStatic ( did, _) ) => {
306
- let const_expr = lookup_const_by_id ( self . tcx , did) . unwrap ( ) ;
307
- const_expr_to_pat ( self . tcx , const_expr)
333
+ Some ( DefStatic ( did, _) ) => match lookup_const_by_id ( self . tcx , did) {
334
+ Some ( const_expr) => box ( GC ) Pat {
335
+ span : pat. span ,
336
+ ..( * const_expr_to_pat ( self . tcx , const_expr) ) . clone ( )
337
+ } ,
338
+ None => {
339
+ self . failed = true ;
340
+ span_err ! ( self . tcx. sess, pat. span, E0158 ,
341
+ "extern statics cannot be referenced in patterns" ) ;
342
+ pat
343
+ }
308
344
} ,
309
345
_ => noop_fold_pat ( pat, self )
310
346
}
@@ -813,7 +849,7 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
813
849
LocalFor => "`for` loop"
814
850
} ;
815
851
816
- let mut static_inliner = StaticInliner { tcx : cx. tcx } ;
852
+ let mut static_inliner = StaticInliner :: new ( cx. tcx ) ;
817
853
match is_refutable ( cx, static_inliner. fold_pat ( loc. pat ) ) {
818
854
Some ( pat) => {
819
855
span_err ! ( cx. tcx. sess, loc. pat. span, E0005 ,
0 commit comments