9
9
// except according to those terms.
10
10
11
11
use middle:: const_eval:: { compare_const_vals, const_bool, const_float, const_nil, const_val} ;
12
- use middle:: const_eval:: { eval_const_expr, lookup_const_by_id} ;
12
+ use middle:: const_eval:: { const_expr_to_pat , eval_const_expr, lookup_const_by_id} ;
13
13
use middle:: def:: * ;
14
14
use middle:: pat_util:: * ;
15
15
use middle:: ty:: * ;
@@ -21,8 +21,9 @@ use std::iter::range_inclusive;
21
21
use syntax:: ast:: * ;
22
22
use syntax:: ast_util:: { is_unguarded, walk_pat} ;
23
23
use syntax:: codemap:: { Span , Spanned , DUMMY_SP } ;
24
- use syntax:: owned_slice :: OwnedSlice ;
24
+ use syntax:: fold :: { Folder , noop_fold_pat } ;
25
25
use syntax:: print:: pprust:: pat_to_string;
26
+ use syntax:: parse:: token;
26
27
use syntax:: visit;
27
28
use syntax:: visit:: { Visitor , FnKind } ;
28
29
use util:: ppaux:: ty_to_string;
@@ -76,6 +77,12 @@ impl fmt::Show for Matrix {
76
77
}
77
78
}
78
79
80
+ impl FromIterator < Vec < Gc < Pat > > > for Matrix {
81
+ fn from_iter < T : Iterator < Vec < Gc < Pat > > > > ( mut iterator : T ) -> Matrix {
82
+ Matrix ( iterator. collect ( ) )
83
+ }
84
+ }
85
+
79
86
pub struct MatchCheckCtxt < ' a > {
80
87
pub tcx : & ' a ty:: ctxt
81
88
}
@@ -120,10 +127,8 @@ impl<'a> Visitor<()> for MatchCheckCtxt<'a> {
120
127
}
121
128
122
129
pub fn check_crate ( tcx : & ty:: ctxt , krate : & Crate ) {
123
- let mut cx = MatchCheckCtxt { tcx : tcx, } ;
124
-
130
+ let mut cx = MatchCheckCtxt { tcx : tcx } ;
125
131
visit:: walk_crate ( & mut cx, krate, ( ) ) ;
126
-
127
132
tcx. sess . abort_if_errors ( ) ;
128
133
}
129
134
@@ -155,48 +160,49 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
155
160
// If the type *is* empty, it's vacuously exhaustive
156
161
return ;
157
162
}
158
- let m: Matrix = Matrix ( arms
163
+
164
+ let mut static_inliner = StaticInliner { tcx : cx. tcx } ;
165
+ let matrix: Matrix = arms
159
166
. iter ( )
160
167
. filter ( |& arm| is_unguarded ( arm) )
161
168
. flat_map ( |arm| arm. pats . iter ( ) )
162
- . map ( |pat| vec ! ( pat . clone ( ) ) )
163
- . collect ( ) ) ;
164
- check_exhaustive ( cx, ex. span , & m ) ;
169
+ . map ( |pat| vec ! [ static_inliner . fold_pat ( * pat ) ] )
170
+ . collect ( ) ;
171
+ check_exhaustive ( cx, ex. span , & matrix ) ;
165
172
} ,
166
173
_ => ( )
167
174
}
168
175
}
169
176
177
+ fn is_expr_const_nan ( tcx : & ty:: ctxt , expr : & Expr ) -> bool {
178
+ match eval_const_expr ( tcx, expr) {
179
+ const_float( f) => f. is_nan ( ) ,
180
+ _ => false
181
+ }
182
+ }
183
+
170
184
// Check for unreachable patterns
171
185
fn check_arms ( cx : & MatchCheckCtxt , arms : & [ Arm ] ) {
172
186
let mut seen = Matrix ( vec ! ( ) ) ;
187
+ let mut static_inliner = StaticInliner { tcx : cx. tcx } ;
173
188
for arm in arms. iter ( ) {
174
189
for pat in arm. pats . iter ( ) {
190
+ let inlined = static_inliner. fold_pat ( * pat) ;
191
+
175
192
// Check that we do not match against a static NaN (#6804)
176
- let pat_matches_nan: |& Pat | -> bool = |p| {
177
- let opt_def = cx. tcx . def_map . borrow ( ) . find_copy ( & p. id ) ;
178
- match opt_def {
179
- Some ( DefStatic ( did, false ) ) => {
180
- let const_expr = lookup_const_by_id ( cx. tcx , did) . unwrap ( ) ;
181
- match eval_const_expr ( cx. tcx , & * const_expr) {
182
- const_float( f) if f. is_nan ( ) => true ,
183
- _ => false
184
- }
193
+ walk_pat ( & * inlined, |p| {
194
+ match p. node {
195
+ PatLit ( expr) if is_expr_const_nan ( cx. tcx , & * expr) => {
196
+ span_warn ! ( cx. tcx. sess, pat. span, E0003 ,
197
+ "unmatchable NaN in pattern, \
198
+ use the is_nan method in a guard instead") ;
185
199
}
186
- _ => false
187
- }
188
- } ;
189
-
190
- walk_pat ( & * * pat, |p| {
191
- if pat_matches_nan ( p) {
192
- span_warn ! ( cx. tcx. sess, p. span, E0003 ,
193
- "unmatchable NaN in pattern, use the is_nan method in a guard instead"
194
- ) ;
200
+ _ => ( )
195
201
}
196
202
true
197
203
} ) ;
198
204
199
- let v = vec ! ( * pat ) ;
205
+ let v = vec ! [ inlined ] ;
200
206
match is_useful ( cx, & seen, v. as_slice ( ) , LeaveOutWitness ) {
201
207
NotUseful => span_err ! ( cx. tcx. sess, pat. span, E0001 , "unreachable pattern" ) ,
202
208
Useful => ( ) ,
@@ -218,8 +224,8 @@ fn raw_pat(p: Gc<Pat>) -> Gc<Pat> {
218
224
}
219
225
}
220
226
221
- fn check_exhaustive ( cx : & MatchCheckCtxt , sp : Span , m : & Matrix ) {
222
- match is_useful ( cx, m , [ wild ( ) ] , ConstructWitness ) {
227
+ fn check_exhaustive ( cx : & MatchCheckCtxt , sp : Span , matrix : & Matrix ) {
228
+ match is_useful ( cx, matrix , [ wild ( ) ] , ConstructWitness ) {
223
229
UsefulWithWitness ( pats) => {
224
230
let witness = match pats. as_slice ( ) {
225
231
[ witness] => witness,
@@ -251,16 +257,26 @@ fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
251
257
}
252
258
}
253
259
254
- fn def_to_path ( tcx : & ty:: ctxt , id : DefId ) -> Path {
255
- ty:: with_path ( tcx, id, |mut path| Path {
256
- global : false ,
257
- segments : path. last ( ) . map ( |elem| PathSegment {
258
- identifier : Ident :: new ( elem. name ( ) ) ,
259
- lifetimes : vec ! ( ) ,
260
- types : OwnedSlice :: empty ( )
261
- } ) . move_iter ( ) . collect ( ) ,
262
- span : DUMMY_SP ,
263
- } )
260
+ pub struct StaticInliner < ' a > {
261
+ pub tcx : & ' a ty:: ctxt
262
+ }
263
+
264
+ impl < ' a > Folder for StaticInliner < ' a > {
265
+ fn fold_pat ( & mut self , pat : Gc < Pat > ) -> Gc < Pat > {
266
+ match pat. node {
267
+ PatIdent ( ..) | PatEnum ( ..) => {
268
+ let def = self . tcx . def_map . borrow ( ) . find_copy ( & pat. id ) ;
269
+ match def {
270
+ Some ( DefStatic ( did, _) ) => {
271
+ let const_expr = lookup_const_by_id ( self . tcx , did) . unwrap ( ) ;
272
+ const_expr_to_pat ( self . tcx , const_expr)
273
+ } ,
274
+ _ => noop_fold_pat ( pat, self )
275
+ }
276
+ }
277
+ _ => noop_fold_pat ( pat, self )
278
+ }
279
+ }
264
280
}
265
281
266
282
/// Constructs a partial witness for a pattern given a list of
@@ -283,9 +299,11 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor,
283
299
284
300
ty:: ty_enum( cid, _) | ty:: ty_struct( cid, _) => {
285
301
let ( vid, is_structure) = match ctor {
286
- & Variant ( vid) => ( vid,
287
- ty:: enum_variant_with_id ( cx. tcx , cid, vid) . arg_names . is_some ( ) ) ,
288
- _ => ( cid, true )
302
+ & Variant ( vid) =>
303
+ ( vid, ty:: enum_variant_with_id ( cx. tcx , cid, vid) . arg_names . is_some ( ) ) ,
304
+ _ =>
305
+ ( cid, ty:: lookup_struct_fields ( cx. tcx , cid) . iter ( )
306
+ . any ( |field| field. name != token:: special_idents:: unnamed_field. name ) )
289
307
} ;
290
308
if is_structure {
291
309
let fields = ty:: lookup_struct_fields ( cx. tcx , vid) ;
@@ -459,8 +477,7 @@ fn is_useful(cx: &MatchCheckCtxt, matrix @ &Matrix(ref rows): &Matrix,
459
477
} ,
460
478
461
479
Some ( constructor) => {
462
- let matrix = Matrix ( rows. iter ( ) . filter_map ( |r|
463
- default ( cx, r. as_slice ( ) ) ) . collect ( ) ) ;
480
+ let matrix = rows. iter ( ) . filter_map ( |r| default ( cx, r. as_slice ( ) ) ) . collect ( ) ;
464
481
match is_useful ( cx, & matrix, v. tail ( ) , witness) {
465
482
UsefulWithWitness ( pats) => {
466
483
let arity = constructor_arity ( cx, & constructor, left_ty) ;
@@ -506,25 +523,23 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: Gc<Pat>,
506
523
match pat. node {
507
524
PatIdent ( ..) =>
508
525
match cx. tcx . def_map . borrow ( ) . find ( & pat. id ) {
509
- Some ( & DefStatic ( did, false ) ) => {
510
- let const_expr = lookup_const_by_id ( cx. tcx , did) . unwrap ( ) ;
511
- vec ! ( ConstantValue ( eval_const_expr( cx. tcx, & * const_expr) ) )
512
- } ,
526
+ Some ( & DefStatic ( ..) ) =>
527
+ cx. tcx . sess . span_bug ( pat. span , "static pattern should've been rewritten" ) ,
513
528
Some ( & DefStruct ( _) ) => vec ! ( Single ) ,
514
529
Some ( & DefVariant ( _, id, _) ) => vec ! ( Variant ( id) ) ,
515
530
_ => vec ! ( )
516
531
} ,
517
532
PatEnum ( ..) =>
518
533
match cx. tcx . def_map . borrow ( ) . find ( & pat. id ) {
519
- Some ( & DefStatic ( did, false ) ) => {
520
- let const_expr = lookup_const_by_id ( cx. tcx , did) . unwrap ( ) ;
521
- vec ! ( ConstantValue ( eval_const_expr( cx. tcx, & * const_expr) ) )
522
- } ,
534
+ Some ( & DefStatic ( ..) ) =>
535
+ cx. tcx . sess . span_bug ( pat. span , "static pattern should've been rewritten" ) ,
523
536
Some ( & DefVariant ( _, id, _) ) => vec ! ( Variant ( id) ) ,
524
537
_ => vec ! ( Single )
525
538
} ,
526
539
PatStruct ( ..) =>
527
540
match cx. tcx . def_map . borrow ( ) . find ( & pat. id ) {
541
+ Some ( & DefStatic ( ..) ) =>
542
+ cx. tcx . sess . span_bug ( pat. span , "static pattern should've been rewritten" ) ,
528
543
Some ( & DefVariant ( _, id, _) ) => vec ! ( Variant ( id) ) ,
529
544
_ => vec ! ( Single )
530
545
} ,
@@ -583,7 +598,7 @@ pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) ->
583
598
}
584
599
585
600
fn range_covered_by_constructor ( ctor : & Constructor ,
586
- from : & const_val , to : & const_val ) -> Option < bool > {
601
+ from : & const_val , to : & const_val ) -> Option < bool > {
587
602
let ( c_from, c_to) = match * ctor {
588
603
ConstantValue ( ref value) => ( value, value) ,
589
604
ConstantRange ( ref from, ref to) => ( from, to) ,
@@ -621,44 +636,22 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
621
636
& PatIdent ( _, _, _) => {
622
637
let opt_def = cx. tcx . def_map . borrow ( ) . find_copy ( & pat_id) ;
623
638
match opt_def {
639
+ Some ( DefStatic ( ..) ) =>
640
+ cx. tcx . sess . span_bug ( pat_span, "static pattern should've been rewritten" ) ,
624
641
Some ( DefVariant ( _, id, _) ) => if * constructor == Variant ( id) {
625
642
Some ( vec ! ( ) )
626
643
} else {
627
644
None
628
645
} ,
629
- Some ( DefStatic ( did, _) ) => {
630
- let const_expr = lookup_const_by_id ( cx. tcx , did) . unwrap ( ) ;
631
- let e_v = eval_const_expr ( cx. tcx , & * const_expr) ;
632
- match range_covered_by_constructor ( constructor, & e_v, & e_v) {
633
- Some ( true ) => Some ( vec ! ( ) ) ,
634
- Some ( false ) => None ,
635
- None => {
636
- cx. tcx . sess . span_err ( pat_span, "mismatched types between arms" ) ;
637
- None
638
- }
639
- }
640
- }
641
- _ => {
642
- Some ( Vec :: from_elem ( arity, wild ( ) ) )
643
- }
646
+ _ => Some ( Vec :: from_elem ( arity, wild ( ) ) )
644
647
}
645
648
}
646
649
647
650
& PatEnum ( _, ref args) => {
648
651
let def = cx. tcx . def_map . borrow ( ) . get_copy ( & pat_id) ;
649
652
match def {
650
- DefStatic ( did, _) => {
651
- let const_expr = lookup_const_by_id ( cx. tcx , did) . unwrap ( ) ;
652
- let e_v = eval_const_expr ( cx. tcx , & * const_expr) ;
653
- match range_covered_by_constructor ( constructor, & e_v, & e_v) {
654
- Some ( true ) => Some ( vec ! ( ) ) ,
655
- Some ( false ) => None ,
656
- None => {
657
- cx. tcx . sess . span_err ( pat_span, "mismatched types between arms" ) ;
658
- None
659
- }
660
- }
661
- }
653
+ DefStatic ( ..) =>
654
+ cx. tcx . sess . span_bug ( pat_span, "static pattern should've been rewritten" ) ,
662
655
DefVariant ( _, id, _) if * constructor != Variant ( id) => None ,
663
656
DefVariant ( ..) | DefFn ( ..) | DefStruct ( ..) => {
664
657
Some ( match args {
@@ -674,6 +667,8 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
674
667
// Is this a struct or an enum variant?
675
668
let def = cx. tcx . def_map . borrow ( ) . get_copy ( & pat_id) ;
676
669
let class_id = match def {
670
+ DefStatic ( ..) =>
671
+ cx. tcx . sess . span_bug ( pat_span, "static pattern should've been rewritten" ) ,
677
672
DefVariant ( _, variant_id, _) => if * constructor == Variant ( variant_id) {
678
673
Some ( variant_id)
679
674
} else {
@@ -782,7 +777,8 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
782
777
LocalFor => "`for` loop"
783
778
} ;
784
779
785
- match is_refutable ( cx, loc. pat ) {
780
+ let mut static_inliner = StaticInliner { tcx : cx. tcx } ;
781
+ match is_refutable ( cx, static_inliner. fold_pat ( loc. pat ) ) {
786
782
Some ( pat) => {
787
783
span_err ! ( cx. tcx. sess, loc. pat. span, E0005 ,
788
784
"refutable pattern in {} binding: `{}` not covered" ,
0 commit comments