8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use _match:: { MatchCheckCtxt , Matrix , lower_pat , is_useful} ;
11
+ use _match:: { MatchCheckCtxt , Matrix , expand_pattern , is_useful} ;
12
12
use _match:: { DUMMY_WILD_PAT } ;
13
13
use _match:: Usefulness :: * ;
14
14
use _match:: WitnessPreference :: * ;
15
15
16
+ use pattern:: { Pattern , PatternContext , PatternError } ;
17
+
16
18
use 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 ;
19
19
20
20
use rustc:: dep_graph:: DepNode ;
21
21
22
22
use rustc:: hir:: pat_util:: { pat_bindings, pat_contains_bindings} ;
23
23
24
- use rustc:: middle:: const_val:: ConstVal ;
25
24
use rustc:: middle:: expr_use_visitor:: { ConsumeMode , Delegate , ExprUseVisitor } ;
26
25
use rustc:: middle:: expr_use_visitor:: { LoanCause , MutateMode } ;
27
26
use rustc:: middle:: expr_use_visitor as euv;
@@ -39,9 +38,7 @@ use rustc::hir::{self, Pat, PatKind};
39
38
use rustc_back:: slice;
40
39
41
40
use syntax:: ast;
42
- use syntax:: codemap:: Spanned ;
43
41
use syntax:: ptr:: P ;
44
- use syntax:: util:: move_map:: MoveMap ;
45
42
use syntax_pos:: Span ;
46
43
47
44
struct OuterVisitor < ' a , ' tcx : ' a > { tcx : TyCtxt < ' a , ' tcx , ' tcx > }
@@ -80,9 +77,6 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
80
77
}
81
78
}
82
79
83
- impl < ' a , ' tcx > OuterVisitor < ' a , ' tcx > {
84
- }
85
-
86
80
pub fn check_crate < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ) {
87
81
tcx. visit_all_items_in_krate ( DepNode :: MatchCheck , & mut OuterVisitor { tcx : tcx } ) ;
88
82
tcx. sess . abort_if_errors ( ) ;
@@ -112,8 +106,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> {
112
106
fn visit_local ( & mut self , loc : & hir:: Local ) {
113
107
intravisit:: walk_local ( self , loc) ;
114
108
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 ) ;
117
110
118
111
// Check legality of move bindings and `@` patterns.
119
112
self . check_patterns ( false , slice:: ref_slice ( & loc. pat ) ) ;
@@ -138,6 +131,27 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
138
131
}
139
132
}
140
133
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
+
141
155
fn check_match (
142
156
& self ,
143
157
scrut : & hir:: Expr ,
@@ -154,32 +168,36 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
154
168
if let Some ( ref guard) = arm. guard {
155
169
check_for_mutation_in_guard ( self , & guard) ;
156
170
}
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 > ) > > ( ) ;
165
171
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
+ }
169
176
}
170
177
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 ( ) ;
174
193
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
+ }
179
198
180
- MatchCheckCtxt :: create_and_enter ( self . tcx , |ref cx| {
181
199
// Fourth, check for unreachable arms.
182
- check_arms ( cx, & inlined_arms[ .. ] , source) ;
200
+ check_arms ( cx, & inlined_arms, source) ;
183
201
184
202
// Finally, check if the whole match expression is exhaustive.
185
203
// Check for empty enum, because is_useful only works on inhabited types.
@@ -204,7 +222,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
204
222
. iter ( )
205
223
. filter ( |& & ( _, guard) | guard. is_none ( ) )
206
224
. flat_map ( |arm| & arm. 0 )
207
- . map ( |pat| vec ! [ lower_pat ( cx , & pat) ] )
225
+ . map ( |pat| vec ! [ pat. 0 ] )
208
226
. collect ( ) ;
209
227
check_exhaustive ( cx, scrut. span , & matrix, source) ;
210
228
} )
@@ -218,8 +236,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
218
236
} ;
219
237
220
238
MatchCheckCtxt :: create_and_enter ( self . tcx , |ref cx| {
239
+ let mut patcx = PatternContext :: new ( self . tcx ) ;
221
240
let pats : Matrix = vec ! [ vec![
222
- lower_pat ( cx, pat)
241
+ expand_pattern ( cx, patcx . lower_pattern ( pat) )
223
242
] ] . into_iter ( ) . collect ( ) ;
224
243
225
244
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) {
269
288
} ) ;
270
289
}
271
290
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
-
293
291
/// Checks for common cases of "catchall" patterns that may not be intended as such.
294
292
fn pat_is_catchall ( dm : & DefMap , pat : & Pat ) -> bool {
295
293
match pat. node {
@@ -304,15 +302,16 @@ fn pat_is_catchall(dm: &DefMap, pat: &Pat) -> bool {
304
302
}
305
303
306
304
// 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
+ {
310
309
let mut seen = Matrix :: empty ( ) ;
311
310
let mut catchall = None ;
312
311
let mut printed_if_let_err = false ;
313
312
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] ;
316
315
317
316
match is_useful ( cx, & seen, & v[ ..] , LeaveOutWitness ) {
318
317
NotUseful => {
@@ -325,7 +324,7 @@ fn check_arms(cx: &MatchCheckCtxt,
325
324
// find the first arm pattern so we can use its span
326
325
let & ( ref first_arm_pats, _) = & arms[ 0 ] ;
327
326
let first_pat = & first_arm_pats[ 0 ] ;
328
- let span = first_pat. span ;
327
+ let span = first_pat. 0 . span ;
329
328
struct_span_err ! ( cx. tcx. sess, span, E0162 ,
330
329
"irrefutable if-let pattern" )
331
330
. span_label ( span, & format ! ( "irrefutable pattern" ) )
@@ -338,7 +337,7 @@ fn check_arms(cx: &MatchCheckCtxt,
338
337
// find the first arm pattern so we can use its span
339
338
let & ( ref first_arm_pats, _) = & arms[ 0 ] ;
340
339
let first_pat = & first_arm_pats[ 0 ] ;
341
- let span = first_pat. span ;
340
+ let span = first_pat. 0 . span ;
342
341
struct_span_err ! ( cx. tcx. sess, span, E0165 ,
343
342
"irrefutable while-let pattern" )
344
343
. span_label ( span, & format ! ( "irrefutable pattern" ) )
@@ -374,7 +373,7 @@ fn check_arms(cx: &MatchCheckCtxt,
374
373
}
375
374
if guard. is_none ( ) {
376
375
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 ) {
378
377
catchall = Some ( pat. span ) ;
379
378
}
380
379
}
@@ -448,97 +447,6 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
448
447
}
449
448
}
450
449
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
-
542
450
// Legality of move bindings checking
543
451
fn check_legality_of_move_bindings ( cx : & MatchVisitor ,
544
452
has_guard : bool ,
0 commit comments