88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- use _match:: { MatchCheckCtxt , Matrix , lower_pat , is_useful} ;
11+ use _match:: { MatchCheckCtxt , Matrix , expand_pattern , is_useful} ;
1212use _match:: { DUMMY_WILD_PAT } ;
1313use _match:: Usefulness :: * ;
1414use _match:: WitnessPreference :: * ;
1515
16+ use pattern:: { Pattern , PatternContext , PatternError } ;
17+
1618use eval:: report_const_eval_err;
17- use eval:: { eval_const_expr_partial, const_expr_to_pat, lookup_const_by_id} ;
18- use eval:: EvalHint :: ExprTypeChecked ;
1919
2020use rustc:: dep_graph:: DepNode ;
2121
2222use rustc:: hir:: pat_util:: { pat_bindings, pat_contains_bindings} ;
2323
24- use rustc:: middle:: const_val:: ConstVal ;
2524use rustc:: middle:: expr_use_visitor:: { ConsumeMode , Delegate , ExprUseVisitor } ;
2625use rustc:: middle:: expr_use_visitor:: { LoanCause , MutateMode } ;
2726use rustc:: middle:: expr_use_visitor as euv;
@@ -39,9 +38,7 @@ use rustc::hir::{self, Pat, PatKind};
3938use rustc_back:: slice;
4039
4140use syntax:: ast;
42- use syntax:: codemap:: Spanned ;
4341use syntax:: ptr:: P ;
44- use syntax:: util:: move_map:: MoveMap ;
4542use syntax_pos:: Span ;
4643
4744struct OuterVisitor < ' a , ' tcx : ' a > { tcx : TyCtxt < ' a , ' tcx , ' tcx > }
@@ -80,9 +77,6 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
8077 }
8178}
8279
83- impl < ' a , ' tcx > OuterVisitor < ' a , ' tcx > {
84- }
85-
8680pub fn check_crate < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ) {
8781 tcx. visit_all_items_in_krate ( DepNode :: MatchCheck , & mut OuterVisitor { tcx : tcx } ) ;
8882 tcx. sess . abort_if_errors ( ) ;
@@ -112,8 +106,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> {
112106 fn visit_local ( & mut self , loc : & hir:: Local ) {
113107 intravisit:: walk_local ( self , loc) ;
114108
115- let pat = StaticInliner :: new ( self . tcx ) . fold_pat ( loc. pat . clone ( ) ) ;
116- self . check_irrefutable ( & pat, false ) ;
109+ self . check_irrefutable ( & loc. pat , false ) ;
117110
118111 // Check legality of move bindings and `@` patterns.
119112 self . check_patterns ( false , slice:: ref_slice ( & loc. pat ) ) ;
@@ -138,6 +131,27 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
138131 }
139132 }
140133
134+ fn report_inlining_errors ( & self , patcx : PatternContext , pat_span : Span ) {
135+ for error in patcx. errors {
136+ match error {
137+ PatternError :: BadConstInPattern ( span, def_id) => {
138+ self . tcx . sess . span_err (
139+ span,
140+ & format ! ( "constants of the type `{}` \
141+ cannot be used in patterns",
142+ self . tcx. item_path_str( def_id) ) ) ;
143+ }
144+ PatternError :: StaticInPattern ( span) => {
145+ span_err ! ( self . tcx. sess, span, E0158 ,
146+ "statics cannot be referenced in patterns" ) ;
147+ }
148+ PatternError :: ConstEval ( err) => {
149+ report_const_eval_err ( self . tcx , & err, pat_span, "pattern" ) . emit ( ) ;
150+ }
151+ }
152+ }
153+ }
154+
141155 fn check_match (
142156 & self ,
143157 scrut : & hir:: Expr ,
@@ -154,32 +168,36 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
154168 if let Some ( ref guard) = arm. guard {
155169 check_for_mutation_in_guard ( self , & guard) ;
156170 }
157- }
158-
159- let mut static_inliner = StaticInliner :: new ( self . tcx ) ;
160- let inlined_arms = arms. iter ( ) . map ( |arm| {
161- ( arm. pats . iter ( ) . map ( |pat| {
162- static_inliner. fold_pat ( ( * pat) . clone ( ) )
163- } ) . collect ( ) , arm. guard . as_ref ( ) . map ( |e| & * * e) )
164- } ) . collect :: < Vec < ( Vec < P < Pat > > , Option < & hir:: Expr > ) > > ( ) ;
165171
166- // Bail out early if inlining failed.
167- if static_inliner. failed {
168- return ;
172+ // Third, perform some lints.
173+ for pat in & arm. pats {
174+ check_for_bindings_named_the_same_as_variants ( self , pat) ;
175+ }
169176 }
170177
171- for pat in inlined_arms. iter ( ) . flat_map ( |& ( ref pats, _) | pats) {
172- // Fourth, check if there are any references to NaN that we should warn about.
173- check_for_static_nan ( self , & pat) ;
178+ MatchCheckCtxt :: create_and_enter ( self . tcx , |ref cx| {
179+ let mut have_errors = false ;
180+
181+ let inlined_arms : Vec < ( Vec < _ > , _ ) > = arms. iter ( ) . map ( |arm| (
182+ arm. pats . iter ( ) . map ( |pat| {
183+ let mut patcx = PatternContext :: new ( self . tcx ) ;
184+ let pattern = expand_pattern ( cx, patcx. lower_pattern ( & pat) ) ;
185+ if !patcx. errors . is_empty ( ) {
186+ self . report_inlining_errors ( patcx, pat. span ) ;
187+ have_errors = true ;
188+ }
189+ ( pattern, & * * pat)
190+ } ) . collect ( ) ,
191+ arm. guard . as_ref ( ) . map ( |e| & * * e)
192+ ) ) . collect ( ) ;
174193
175- // Fifth, check if for any of the patterns that match an enumerated type
176- // are bindings with the same name as one of the variants of said type.
177- check_for_bindings_named_the_same_as_variants ( self , & pat ) ;
178- }
194+ // Bail out early if inlining failed.
195+ if have_errors {
196+ return ;
197+ }
179198
180- MatchCheckCtxt :: create_and_enter ( self . tcx , |ref cx| {
181199 // Fourth, check for unreachable arms.
182- check_arms ( cx, & inlined_arms[ .. ] , source) ;
200+ check_arms ( cx, & inlined_arms, source) ;
183201
184202 // Finally, check if the whole match expression is exhaustive.
185203 // Check for empty enum, because is_useful only works on inhabited types.
@@ -204,7 +222,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
204222 . iter ( )
205223 . filter ( |& & ( _, guard) | guard. is_none ( ) )
206224 . flat_map ( |arm| & arm. 0 )
207- . map ( |pat| vec ! [ lower_pat ( cx , & pat) ] )
225+ . map ( |pat| vec ! [ pat. 0 ] )
208226 . collect ( ) ;
209227 check_exhaustive ( cx, scrut. span , & matrix, source) ;
210228 } )
@@ -218,8 +236,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
218236 } ;
219237
220238 MatchCheckCtxt :: create_and_enter ( self . tcx , |ref cx| {
239+ let mut patcx = PatternContext :: new ( self . tcx ) ;
221240 let pats : Matrix = vec ! [ vec![
222- lower_pat ( cx, pat)
241+ expand_pattern ( cx, patcx . lower_pattern ( pat) )
223242 ] ] . into_iter ( ) . collect ( ) ;
224243
225244 let witness = match is_useful ( cx, & pats, & [ cx. wild_pattern ] , ConstructWitness ) {
@@ -269,27 +288,6 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
269288 } ) ;
270289}
271290
272- // Check that we do not match against a static NaN (#6804)
273- fn check_for_static_nan ( cx : & MatchVisitor , pat : & Pat ) {
274- pat. walk ( |p| {
275- if let PatKind :: Lit ( ref expr) = p. node {
276- match eval_const_expr_partial ( cx. tcx , & expr, ExprTypeChecked , None ) {
277- Ok ( ConstVal :: Float ( f) ) if f. is_nan ( ) => {
278- span_warn ! ( cx. tcx. sess, p. span, E0003 ,
279- "unmatchable NaN in pattern, \
280- use the is_nan method in a guard instead") ;
281- }
282- Ok ( _) => { }
283-
284- Err ( err) => {
285- report_const_eval_err ( cx. tcx , & err, p. span , "pattern" ) . emit ( ) ;
286- }
287- }
288- }
289- true
290- } ) ;
291- }
292-
293291/// Checks for common cases of "catchall" patterns that may not be intended as such.
294292fn pat_is_catchall ( dm : & DefMap , pat : & Pat ) -> bool {
295293 match pat. node {
@@ -304,15 +302,16 @@ fn pat_is_catchall(dm: &DefMap, pat: &Pat) -> bool {
304302}
305303
306304// Check for unreachable patterns
307- fn check_arms ( cx : & MatchCheckCtxt ,
308- arms : & [ ( Vec < P < Pat > > , Option < & hir:: Expr > ) ] ,
309- source : hir:: MatchSource ) {
305+ fn check_arms < ' a , ' tcx > ( cx : & MatchCheckCtxt < ' a , ' tcx > ,
306+ arms : & [ ( Vec < ( & Pattern < ' tcx > , & ' a hir:: Pat ) > , Option < & hir:: Expr > ) ] ,
307+ source : hir:: MatchSource )
308+ {
310309 let mut seen = Matrix :: empty ( ) ;
311310 let mut catchall = None ;
312311 let mut printed_if_let_err = false ;
313312 for & ( ref pats, guard) in arms {
314- for pat in pats {
315- let v = vec ! [ lower_pat ( cx , & pat) ] ;
313+ for & ( pat, hir_pat ) in pats {
314+ let v = vec ! [ pat] ;
316315
317316 match is_useful ( cx, & seen, & v[ ..] , LeaveOutWitness ) {
318317 NotUseful => {
@@ -325,7 +324,7 @@ fn check_arms(cx: &MatchCheckCtxt,
325324 // find the first arm pattern so we can use its span
326325 let & ( ref first_arm_pats, _) = & arms[ 0 ] ;
327326 let first_pat = & first_arm_pats[ 0 ] ;
328- let span = first_pat. span ;
327+ let span = first_pat. 0 . span ;
329328 struct_span_err ! ( cx. tcx. sess, span, E0162 ,
330329 "irrefutable if-let pattern" )
331330 . span_label ( span, & format ! ( "irrefutable pattern" ) )
@@ -338,7 +337,7 @@ fn check_arms(cx: &MatchCheckCtxt,
338337 // find the first arm pattern so we can use its span
339338 let & ( ref first_arm_pats, _) = & arms[ 0 ] ;
340339 let first_pat = & first_arm_pats[ 0 ] ;
341- let span = first_pat. span ;
340+ let span = first_pat. 0 . span ;
342341 struct_span_err ! ( cx. tcx. sess, span, E0165 ,
343342 "irrefutable while-let pattern" )
344343 . span_label ( span, & format ! ( "irrefutable pattern" ) )
@@ -374,7 +373,7 @@ fn check_arms(cx: &MatchCheckCtxt,
374373 }
375374 if guard. is_none ( ) {
376375 seen. push ( v) ;
377- if catchall. is_none ( ) && pat_is_catchall ( & cx. tcx . def_map . borrow ( ) , pat ) {
376+ if catchall. is_none ( ) && pat_is_catchall ( & cx. tcx . def_map . borrow ( ) , hir_pat ) {
378377 catchall = Some ( pat. span ) ;
379378 }
380379 }
@@ -448,97 +447,6 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
448447 }
449448}
450449
451-
452- struct StaticInliner < ' a , ' tcx : ' a > {
453- tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
454- failed : bool
455- }
456-
457- impl < ' a , ' tcx > StaticInliner < ' a , ' tcx > {
458- pub fn new < ' b > ( tcx : TyCtxt < ' b , ' tcx , ' tcx > ) -> StaticInliner < ' b , ' tcx > {
459- StaticInliner {
460- tcx : tcx,
461- failed : false
462- }
463- }
464- }
465-
466- impl < ' a , ' tcx > StaticInliner < ' a , ' tcx > {
467- fn fold_pat ( & mut self , pat : P < Pat > ) -> P < Pat > {
468- match pat. node {
469- PatKind :: Path ( ..) => {
470- match self . tcx . expect_def ( pat. id ) {
471- Def :: AssociatedConst ( did) | Def :: Const ( did) => {
472- let substs = Some ( self . tcx . node_id_item_substs ( pat. id ) . substs ) ;
473- if let Some ( ( const_expr, _) ) = lookup_const_by_id ( self . tcx , did, substs) {
474- match const_expr_to_pat ( self . tcx , const_expr, pat. id , pat. span ) {
475- Ok ( new_pat) => return new_pat,
476- Err ( def_id) => {
477- self . failed = true ;
478- self . tcx . sess . span_err (
479- pat. span ,
480- & format ! ( "constants of the type `{}` \
481- cannot be used in patterns",
482- self . tcx. item_path_str( def_id) ) ) ;
483- }
484- }
485- } else {
486- self . failed = true ;
487- span_err ! ( self . tcx. sess, pat. span, E0158 ,
488- "statics cannot be referenced in patterns" ) ;
489- }
490- }
491- _ => { }
492- }
493- }
494- _ => { }
495- }
496-
497- pat. map ( |Pat { id, node, span } | {
498- let node = match node {
499- PatKind :: Binding ( binding_mode, pth1, sub) => {
500- PatKind :: Binding ( binding_mode, pth1, sub. map ( |x| self . fold_pat ( x) ) )
501- }
502- PatKind :: TupleStruct ( pth, pats, ddpos) => {
503- PatKind :: TupleStruct ( pth, pats. move_map ( |x| self . fold_pat ( x) ) , ddpos)
504- }
505- PatKind :: Struct ( pth, fields, etc) => {
506- let fs = fields. move_map ( |f| {
507- Spanned {
508- span : f. span ,
509- node : hir:: FieldPat {
510- name : f. node . name ,
511- pat : self . fold_pat ( f. node . pat ) ,
512- is_shorthand : f. node . is_shorthand ,
513- } ,
514- }
515- } ) ;
516- PatKind :: Struct ( pth, fs, etc)
517- }
518- PatKind :: Tuple ( elts, ddpos) => {
519- PatKind :: Tuple ( elts. move_map ( |x| self . fold_pat ( x) ) , ddpos)
520- }
521- PatKind :: Box ( inner) => PatKind :: Box ( self . fold_pat ( inner) ) ,
522- PatKind :: Ref ( inner, mutbl) => PatKind :: Ref ( self . fold_pat ( inner) , mutbl) ,
523- PatKind :: Slice ( before, slice, after) => {
524- PatKind :: Slice ( before. move_map ( |x| self . fold_pat ( x) ) ,
525- slice. map ( |x| self . fold_pat ( x) ) ,
526- after. move_map ( |x| self . fold_pat ( x) ) )
527- }
528- PatKind :: Wild |
529- PatKind :: Lit ( _) |
530- PatKind :: Range ( ..) |
531- PatKind :: Path ( ..) => node
532- } ;
533- Pat {
534- id : id,
535- node : node,
536- span : span
537- }
538- } )
539- }
540- }
541-
542450// Legality of move bindings checking
543451fn check_legality_of_move_bindings ( cx : & MatchVisitor ,
544452 has_guard : bool ,
0 commit comments