@@ -23,7 +23,7 @@ use std::gc::{Gc, GC};
2323use std:: iter:: AdditiveIterator ;
2424use std:: iter:: range_inclusive;
2525use syntax:: ast:: * ;
26- use syntax:: ast_util:: { is_unguarded , walk_pat} ;
26+ use syntax:: ast_util:: walk_pat;
2727use syntax:: codemap:: { Span , Spanned , DUMMY_SP } ;
2828use syntax:: fold:: { Folder , noop_fold_pat} ;
2929use syntax:: print:: pprust:: pat_to_string;
@@ -159,13 +159,31 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
159159 }
160160 }
161161
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 ( ) ) ;
164182
165183 // Finally, check if the whole match expression is exhaustive.
166184 // Check for empty enum, because is_useful only works on inhabited types.
167185 let pat_ty = node_id_to_type ( cx. tcx , scrut. id ) ;
168- if arms . is_empty ( ) {
186+ if inlined_arms . is_empty ( ) {
169187 if !type_is_empty ( cx. tcx , pat_ty) {
170188 // We know the type is inhabited, so this must be wrong
171189 span_err ! ( cx. tcx. sess, ex. span, E0002 ,
@@ -177,19 +195,16 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
177195 return ;
178196 }
179197
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] )
186203 . collect ( ) ;
187204 check_exhaustive ( cx, ex. span , & matrix) ;
188205 } ,
189206 ExprForLoop ( ref pat, _, _, _) => {
190- let mut static_inliner = StaticInliner {
191- tcx : cx. tcx
192- } ;
207+ let mut static_inliner = StaticInliner :: new ( cx. tcx ) ;
193208 match is_refutable ( cx, static_inliner. fold_pat ( * pat) ) {
194209 Some ( uncovered_pat) => {
195210 cx. tcx . sess . span_err (
@@ -216,28 +231,31 @@ fn is_expr_const_nan(tcx: &ty::ctxt, expr: &Expr) -> bool {
216231 }
217232}
218233
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 ] ) {
223236 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| {
229239 match p. node {
230240 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 ,
232242 "unmatchable NaN in pattern, \
233243 use the is_nan method in a guard instead") ;
234244 }
235245 _ => ( )
236246 }
237247 true
238248 } ) ;
249+ }
250+ }
251+ }
239252
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] ;
241259 match is_useful ( cx, & seen, v. as_slice ( ) , LeaveOutWitness ) {
242260 NotUseful => span_err ! ( cx. tcx. sess, pat. span, E0001 , "unreachable pattern" ) ,
243261 Useful => ( ) ,
@@ -293,7 +311,17 @@ fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
293311}
294312
295313pub 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+ }
297325}
298326
299327impl < ' a > Folder for StaticInliner < ' a > {
@@ -302,9 +330,17 @@ impl<'a> Folder for StaticInliner<'a> {
302330 PatIdent ( ..) | PatEnum ( ..) => {
303331 let def = self . tcx . def_map . borrow ( ) . find_copy ( & pat. id ) ;
304332 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+ }
308344 } ,
309345 _ => noop_fold_pat ( pat, self )
310346 }
@@ -813,7 +849,7 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
813849 LocalFor => "`for` loop"
814850 } ;
815851
816- let mut static_inliner = StaticInliner { tcx : cx. tcx } ;
852+ let mut static_inliner = StaticInliner :: new ( cx. tcx ) ;
817853 match is_refutable ( cx, static_inliner. fold_pat ( loc. pat ) ) {
818854 Some ( pat) => {
819855 span_err ! ( cx. tcx. sess, loc. pat. span, E0005 ,
0 commit comments