99// except according to those terms.
1010
1111use 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} ;
1313use middle:: def:: * ;
1414use middle:: pat_util:: * ;
1515use middle:: ty:: * ;
@@ -21,8 +21,9 @@ use std::iter::range_inclusive;
2121use syntax:: ast:: * ;
2222use syntax:: ast_util:: { is_unguarded, walk_pat} ;
2323use syntax:: codemap:: { Span , Spanned , DUMMY_SP } ;
24- use syntax:: owned_slice :: OwnedSlice ;
24+ use syntax:: fold :: { Folder , noop_fold_pat } ;
2525use syntax:: print:: pprust:: pat_to_string;
26+ use syntax:: parse:: token;
2627use syntax:: visit;
2728use syntax:: visit:: { Visitor , FnKind } ;
2829use util:: ppaux:: ty_to_string;
@@ -76,6 +77,12 @@ impl fmt::Show for Matrix {
7677 }
7778}
7879
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+
7986pub struct MatchCheckCtxt < ' a > {
8087 pub tcx : & ' a ty:: ctxt
8188}
@@ -120,10 +127,8 @@ impl<'a> Visitor<()> for MatchCheckCtxt<'a> {
120127}
121128
122129pub fn check_crate ( tcx : & ty:: ctxt , krate : & Crate ) {
123- let mut cx = MatchCheckCtxt { tcx : tcx, } ;
124-
130+ let mut cx = MatchCheckCtxt { tcx : tcx } ;
125131 visit:: walk_crate ( & mut cx, krate, ( ) ) ;
126-
127132 tcx. sess . abort_if_errors ( ) ;
128133}
129134
@@ -155,48 +160,49 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &Expr) {
155160 // If the type *is* empty, it's vacuously exhaustive
156161 return ;
157162 }
158- let m: Matrix = Matrix ( arms
163+
164+ let mut static_inliner = StaticInliner { tcx : cx. tcx } ;
165+ let matrix: Matrix = arms
159166 . iter ( )
160167 . filter ( |& arm| is_unguarded ( arm) )
161168 . 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 ) ;
165172 } ,
166173 _ => ( )
167174 }
168175}
169176
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+
170184// Check for unreachable patterns
171185fn check_arms ( cx : & MatchCheckCtxt , arms : & [ Arm ] ) {
172186 let mut seen = Matrix ( vec ! ( ) ) ;
187+ let mut static_inliner = StaticInliner { tcx : cx. tcx } ;
173188 for arm in arms. iter ( ) {
174189 for pat in arm. pats . iter ( ) {
190+ let inlined = static_inliner. fold_pat ( * pat) ;
191+
175192 // 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") ;
185199 }
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+ _ => ( )
195201 }
196202 true
197203 } ) ;
198204
199- let v = vec ! ( * pat ) ;
205+ let v = vec ! [ inlined ] ;
200206 match is_useful ( cx, & seen, v. as_slice ( ) , LeaveOutWitness ) {
201207 NotUseful => span_err ! ( cx. tcx. sess, pat. span, E0001 , "unreachable pattern" ) ,
202208 Useful => ( ) ,
@@ -218,8 +224,8 @@ fn raw_pat(p: Gc<Pat>) -> Gc<Pat> {
218224 }
219225}
220226
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 ) {
223229 UsefulWithWitness ( pats) => {
224230 let witness = match pats. as_slice ( ) {
225231 [ witness] => witness,
@@ -251,16 +257,26 @@ fn const_val_to_expr(value: &const_val) -> Gc<Expr> {
251257 }
252258}
253259
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+ }
264280}
265281
266282/// Constructs a partial witness for a pattern given a list of
@@ -283,9 +299,11 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor,
283299
284300 ty:: ty_enum( cid, _) | ty:: ty_struct( cid, _) => {
285301 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 ) )
289307 } ;
290308 if is_structure {
291309 let fields = ty:: lookup_struct_fields ( cx. tcx , vid) ;
@@ -459,8 +477,7 @@ fn is_useful(cx: &MatchCheckCtxt, matrix @ &Matrix(ref rows): &Matrix,
459477 } ,
460478
461479 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 ( ) ;
464481 match is_useful ( cx, & matrix, v. tail ( ) , witness) {
465482 UsefulWithWitness ( pats) => {
466483 let arity = constructor_arity ( cx, & constructor, left_ty) ;
@@ -506,25 +523,23 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: Gc<Pat>,
506523 match pat. node {
507524 PatIdent ( ..) =>
508525 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" ) ,
513528 Some ( & DefStruct ( _) ) => vec ! ( Single ) ,
514529 Some ( & DefVariant ( _, id, _) ) => vec ! ( Variant ( id) ) ,
515530 _ => vec ! ( )
516531 } ,
517532 PatEnum ( ..) =>
518533 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" ) ,
523536 Some ( & DefVariant ( _, id, _) ) => vec ! ( Variant ( id) ) ,
524537 _ => vec ! ( Single )
525538 } ,
526539 PatStruct ( ..) =>
527540 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" ) ,
528543 Some ( & DefVariant ( _, id, _) ) => vec ! ( Variant ( id) ) ,
529544 _ => vec ! ( Single )
530545 } ,
@@ -583,7 +598,7 @@ pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) ->
583598}
584599
585600fn range_covered_by_constructor ( ctor : & Constructor ,
586- from : & const_val , to : & const_val ) -> Option < bool > {
601+ from : & const_val , to : & const_val ) -> Option < bool > {
587602 let ( c_from, c_to) = match * ctor {
588603 ConstantValue ( ref value) => ( value, value) ,
589604 ConstantRange ( ref from, ref to) => ( from, to) ,
@@ -621,44 +636,22 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
621636 & PatIdent ( _, _, _) => {
622637 let opt_def = cx. tcx . def_map . borrow ( ) . find_copy ( & pat_id) ;
623638 match opt_def {
639+ Some ( DefStatic ( ..) ) =>
640+ cx. tcx . sess . span_bug ( pat_span, "static pattern should've been rewritten" ) ,
624641 Some ( DefVariant ( _, id, _) ) => if * constructor == Variant ( id) {
625642 Some ( vec ! ( ) )
626643 } else {
627644 None
628645 } ,
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 ( ) ) )
644647 }
645648 }
646649
647650 & PatEnum ( _, ref args) => {
648651 let def = cx. tcx . def_map . borrow ( ) . get_copy ( & pat_id) ;
649652 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" ) ,
662655 DefVariant ( _, id, _) if * constructor != Variant ( id) => None ,
663656 DefVariant ( ..) | DefFn ( ..) | DefStruct ( ..) => {
664657 Some ( match args {
@@ -674,6 +667,8 @@ pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
674667 // Is this a struct or an enum variant?
675668 let def = cx. tcx . def_map . borrow ( ) . get_copy ( & pat_id) ;
676669 let class_id = match def {
670+ DefStatic ( ..) =>
671+ cx. tcx . sess . span_bug ( pat_span, "static pattern should've been rewritten" ) ,
677672 DefVariant ( _, variant_id, _) => if * constructor == Variant ( variant_id) {
678673 Some ( variant_id)
679674 } else {
@@ -782,7 +777,8 @@ fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
782777 LocalFor => "`for` loop"
783778 } ;
784779
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 ) ) {
786782 Some ( pat) => {
787783 span_err ! ( cx. tcx. sess, loc. pat. span, E0005 ,
788784 "refutable pattern in {} binding: `{}` not covered" ,
0 commit comments