@@ -21,7 +21,7 @@ use hair::*;
21
21
use repr:: * ;
22
22
use rustc_data_structures:: fnv:: FnvHashMap ;
23
23
use rustc:: middle:: const_eval:: ConstVal ;
24
- use rustc:: middle:: ty:: Ty ;
24
+ use rustc:: middle:: ty:: { self , Ty } ;
25
25
use syntax:: codemap:: Span ;
26
26
27
27
impl < ' a , ' tcx > Builder < ' a , ' tcx > {
@@ -271,248 +271,172 @@ impl<'a,'tcx> Builder<'a,'tcx> {
271
271
target_blocks
272
272
}
273
273
274
- /// Given a candidate and the outcome of a test we have performed,
275
- /// transforms the candidate into a new candidate that reflects
276
- /// further tests still needed. Returns `None` if this candidate
277
- /// has now been ruled out.
274
+ /// Given that we are performing `test` against `test_lvalue`,
275
+ /// this job sorts out what the status of `candidate` will be
276
+ /// after the test. The `resulting_candidates` vector stores, for
277
+ /// each possible outcome of `test`, a vector of the candidates
278
+ /// that will result. This fn should add a (possibly modified)
279
+ /// clone of candidate into `resulting_candidates` wherever
280
+ /// appropriate.
278
281
///
279
- /// For example, if a candidate included the patterns `[x.0 @
280
- /// Ok(P1), x.1 @ 22]`, and we did a switch test on `x.0` and
281
- /// found the variant `Err` (as indicated by the `test_outcome`
282
- /// parameter), we would return `None`. But if the test_outcome
283
- /// were `Ok`, we would return `Some([x.0.downcast<Ok>.0 @ P1, x.1
284
- /// @ 22])`.
285
- pub fn candidate_under_assumption < ' pat > ( & mut self ,
286
- test_lvalue : & Lvalue < ' tcx > ,
287
- test_kind : & TestKind < ' tcx > ,
288
- test_outcome : usize ,
289
- candidate : & Candidate < ' pat , ' tcx > )
290
- -> Option < Candidate < ' pat , ' tcx > > {
291
- let result = self . match_pairs_under_assumption ( test_lvalue,
292
- test_kind,
293
- test_outcome,
294
- & candidate. match_pairs ) ;
295
- match result {
296
- Some ( match_pairs) => Some ( Candidate { match_pairs : match_pairs,
297
- bindings : candidate. bindings . clone ( ) ,
298
- guard : candidate. guard . clone ( ) ,
299
- arm_index : candidate. arm_index } ) ,
300
- None => None ,
301
- }
302
- }
303
-
304
- /// Helper for candidate_under_assumption that does the actual
305
- /// work of transforming the list of match pairs.
306
- fn match_pairs_under_assumption < ' pat > ( & mut self ,
307
- test_lvalue : & Lvalue < ' tcx > ,
308
- test_kind : & TestKind < ' tcx > ,
309
- test_outcome : usize ,
310
- match_pairs : & [ MatchPair < ' pat , ' tcx > ] )
311
- -> Option < Vec < MatchPair < ' pat , ' tcx > > > {
312
- let mut result = vec ! [ ] ;
313
-
314
- for match_pair in match_pairs {
315
- // If the match pair is either:
316
- // (1) testing a different lvalue; or,
317
- // (2) the test doesn't tell us anything about this match-pair,
318
- // then we have to retain it as for after the test is complete.
319
- if
320
- match_pair. lvalue != * test_lvalue || // (1)
321
- !self . test_informs_match_pair ( match_pair, test_kind, test_outcome) // (2)
322
- {
323
- result. push ( match_pair. clone ( ) ) ;
324
- continue ;
325
- }
326
-
327
- // otherwise, build up the consequence match pairs
328
- let opt_consequent_match_pairs =
329
- self . consequent_match_pairs_under_assumption ( match_pair,
330
- test_kind,
331
- test_outcome) ;
332
- match opt_consequent_match_pairs {
333
- None => {
334
- // Right kind of test, but wrong outcome. That
335
- // means this **entire candidate** is
336
- // inapplicable, since the candidate is only
337
- // applicable if all of its match-pairs apply (and
338
- // this one doesn't).
339
- return None ;
340
- }
341
-
342
- Some ( consequent_match_pairs) => {
343
- // Test passed; add any new patterns we have to test to the final result.
344
- result. extend ( consequent_match_pairs)
345
- }
282
+ /// So, for example, if this candidate is `x @ Some(P0)` and the
283
+ /// test is a variant test, then we would add `(x as Option).0 @
284
+ /// P0` to the `resulting_candidates` entry corresponding to the
285
+ /// variant `Some`.
286
+ ///
287
+ /// In many cases we will add the `candidate` to more than one
288
+ /// outcome. For example, say that the test is `x == 22`, but the
289
+ /// candidate is `x @ 13..55`. In that case, if the test is true,
290
+ /// then we know that the candidate applies (without this match
291
+ /// pair, potentially, though we don't optimize this due to
292
+ /// #29623). If the test is false, the candidate may also apply
293
+ /// (with the match pair, still).
294
+ pub fn sort_candidate < ' pat > ( & mut self ,
295
+ test_lvalue : & Lvalue < ' tcx > ,
296
+ test : & Test < ' tcx > ,
297
+ candidate : & Candidate < ' pat , ' tcx > ,
298
+ resulting_candidates : & mut Vec < Vec < Candidate < ' pat , ' tcx > > > ) {
299
+ // Find the match_pair for this lvalue (if any). At present,
300
+ // afaik, there can be at most one. (In the future, if we
301
+ // adopted a more general `@` operator, there might be more
302
+ // than one, but it'd be very unusual to have two sides that
303
+ // both require tests; you'd expect one side to be simplified
304
+ // away.)
305
+ let tested_match_pair = candidate. match_pairs . iter ( )
306
+ . enumerate ( )
307
+ . filter ( |& ( _, mp) | mp. lvalue == * test_lvalue)
308
+ . next ( ) ;
309
+ let ( match_pair_index, match_pair) = match tested_match_pair {
310
+ Some ( pair) => pair,
311
+ None => {
312
+ // We are not testing this lvalue. Therefore, this
313
+ // candidate applies to ALL outcomes.
314
+ return self . add_to_all_candidate_sets ( candidate, resulting_candidates) ;
346
315
}
347
- }
348
-
349
- Some ( result)
350
- }
316
+ } ;
351
317
352
- /// Given that we executed ` test` to `match_pair.lvalue` with
353
- /// outcome `test_outcome`, does that tell us anything about
354
- /// whether `match_pair` applies?
355
- ///
356
- /// Often it does not. For example, if we are testing whether
357
- /// the discriminant equals 4, and we find that it does not,
358
- /// but the `match_pair` is testing if the discriminant equals 5,
359
- /// that does not help us.
360
- fn test_informs_match_pair < ' pat > ( & mut self ,
361
- match_pair : & MatchPair < ' pat , ' tcx > ,
362
- test_kind : & TestKind < ' tcx > ,
363
- _test_outcome : usize )
364
- -> bool {
365
- match * match_pair . pattern . kind {
366
- PatternKind :: Variant { .. } => {
367
- match * test_kind {
368
- TestKind :: Switch { .. } => true ,
369
- _ => false ,
318
+ match test. kind {
319
+ // If we are performing a variant switch, then this
320
+ // informs variant patterns, but nothing else.
321
+ TestKind :: Switch { adt_def : tested_adt_def } => {
322
+ match * match_pair . pattern . kind {
323
+ PatternKind :: Variant { adt_def , variant_index , ref subpatterns } => {
324
+ assert_eq ! ( adt_def , tested_adt_def ) ;
325
+ let new_candidate =
326
+ self . candidate_after_variant_switch ( match_pair_index ,
327
+ adt_def ,
328
+ variant_index ,
329
+ subpatterns ,
330
+ candidate ) ;
331
+ resulting_candidates [ variant_index ] . push ( new_candidate ) ;
332
+ }
333
+ _ => {
334
+ self . add_to_all_candidate_sets ( candidate , resulting_candidates ) ;
335
+ }
370
336
}
371
337
}
372
338
373
- PatternKind :: Constant { value : Literal :: Value { .. } }
374
- if is_switch_ty ( match_pair. pattern . ty ) => {
375
- match * test_kind {
376
- TestKind :: SwitchInt { .. } => true ,
377
-
378
- // Did not do an integer equality test (which is always a SwitchInt).
379
- // So we learned nothing relevant to this match-pair.
380
- //
381
- // FIXME(#29623) we could use TestKind::Range to rule
382
- // things out here, in some cases.
383
- _ => false ,
339
+ // If we are performing a switch over integers, then this informs integer
340
+ // equality, but nothing else.
341
+ //
342
+ // FIXME(#29623) we could use TestKind::Range to rule
343
+ // things out here, in some cases.
344
+ TestKind :: SwitchInt { switch_ty : _, options : _, ref indices } => {
345
+ match * match_pair. pattern . kind {
346
+ PatternKind :: Constant { value : Literal :: Value { ref value } }
347
+ if is_switch_ty ( match_pair. pattern . ty ) => {
348
+ let index = indices[ value] ;
349
+ let new_candidate = self . candidate_without_match_pair ( match_pair_index,
350
+ candidate) ;
351
+ resulting_candidates[ index] . push ( new_candidate) ;
352
+ }
353
+ _ => {
354
+ self . add_to_all_candidate_sets ( candidate, resulting_candidates) ;
355
+ }
384
356
}
385
357
}
386
358
387
- PatternKind :: Constant { .. } |
388
- PatternKind :: Range { .. } |
389
- PatternKind :: Slice { .. } => {
359
+ TestKind :: Eq { .. } |
360
+ TestKind :: Range { .. } |
361
+ TestKind :: Len { .. } => {
362
+ // These are all binary tests.
363
+ //
364
+ // FIXME(#29623) we can be more clever here
390
365
let pattern_test = self . test ( & match_pair) ;
391
- if pattern_test. kind == * test_kind {
392
- true
366
+ if pattern_test. kind == test. kind {
367
+ let new_candidate = self . candidate_without_match_pair ( match_pair_index,
368
+ candidate) ;
369
+ resulting_candidates[ 0 ] . push ( new_candidate) ;
393
370
} else {
394
- // FIXME(#29623) in all 3 cases, we could sometimes do
395
- // better here. For example, if we are checking
396
- // whether the value is equal to X, and we find
397
- // that it is, that (may) imply value is not equal
398
- // to Y. Or, if the range tested is `3..5`, and
399
- // our range is `4..5`, then we know that our
400
- // range also does not apply. Similarly, if we
401
- // test that length is >= 5, and it fails, we also
402
- // know that length is not >= 7. etc.
403
- false
371
+ self . add_to_all_candidate_sets ( candidate, resulting_candidates) ;
404
372
}
405
373
}
406
-
407
- PatternKind :: Array { .. } |
408
- PatternKind :: Wild |
409
- PatternKind :: Binding { .. } |
410
- PatternKind :: Leaf { .. } |
411
- PatternKind :: Deref { .. } => {
412
- self . error_simplifyable ( & match_pair)
413
- }
414
374
}
415
375
}
416
376
417
- /// Given that we executed `test` with outcome `test_outcome`,
418
- /// what are the resulting match pairs? This can return either:
419
- ///
420
- /// - None, meaning that the test indicated that this outcome
421
- /// means that this match-pair is not the current one for the
422
- /// current discriminant (which rules out the enclosing
423
- /// candidate);
424
- /// - Some(...), meaning that either the test didn't tell us whether this
425
- /// match-pair is correct or not, or that we DID match and now have
426
- /// subsequent matches to perform.
427
- ///
428
- /// As an example, consider:
429
- ///
430
- /// ```
431
- /// match option {
432
- /// Ok(<pattern>) => ...,
433
- /// Err(_) => ...,
434
- /// }
435
- /// ```
436
- ///
437
- /// Suppose that the `test` is a `Switch` and the outcome is
438
- /// `Ok`. Then in that case, the first arm will have a match-pair
439
- /// of `option @ Ok(<pattern>)`. In that case we will return
440
- /// `Some(vec![(option as Ok) @ <pattern>])`. The `Some` reuslt
441
- /// indicates that the match-pair still applies, and we now have
442
- /// to test `(option as Ok) @ <pattern>`.
443
- ///
444
- /// On the second arm, a `None` will be returned, because if we
445
- /// observed that `option` has the discriminant `Ok`, then the
446
- /// second arm cannot apply.
447
- pub fn consequent_match_pairs_under_assumption < ' pat > ( & mut self ,
448
- match_pair : & MatchPair < ' pat , ' tcx > ,
449
- test_kind : & TestKind < ' tcx > ,
450
- test_outcome : usize )
451
- -> Option < Vec < MatchPair < ' pat , ' tcx > > > {
452
- match * match_pair. pattern . kind {
453
- PatternKind :: Variant { adt_def, variant_index, ref subpatterns } => {
454
- assert ! ( match * test_kind { TestKind :: Switch { .. } => true ,
455
- _ => false } ) ;
456
-
457
- if test_outcome != variant_index {
458
- return None ; // Tested, but found the wrong variant.
459
- }
377
+ fn candidate_without_match_pair < ' pat > ( & mut self ,
378
+ match_pair_index : usize ,
379
+ candidate : & Candidate < ' pat , ' tcx > )
380
+ -> Candidate < ' pat , ' tcx > {
381
+ let other_match_pairs =
382
+ candidate. match_pairs . iter ( )
383
+ . enumerate ( )
384
+ . filter ( |& ( index, _) | index != match_pair_index)
385
+ . map ( |( _, mp) | mp. clone ( ) )
386
+ . collect ( ) ;
387
+ Candidate {
388
+ match_pairs : other_match_pairs,
389
+ bindings : candidate. bindings . clone ( ) ,
390
+ guard : candidate. guard . clone ( ) ,
391
+ arm_index : candidate. arm_index ,
392
+ }
393
+ }
460
394
461
- // Correct variant. Extract the subitems and match
462
- // those. The lvalue goes gets downcast, so
463
- // e.g. `foo.bar` becomes `foo.bar as Variant`.
464
- let elem = ProjectionElem :: Downcast ( adt_def, variant_index) ;
465
- let downcast_lvalue = match_pair. lvalue . clone ( ) . elem ( elem) ;
466
- let consequent_match_pairs =
467
- subpatterns. iter ( )
468
- . map ( |subpattern| {
469
- let lvalue =
470
- downcast_lvalue. clone ( ) . field (
471
- subpattern. field ) ;
472
- MatchPair :: new ( lvalue, & subpattern. pattern )
473
- } )
474
- . collect ( ) ;
475
- Some ( consequent_match_pairs)
476
- }
395
+ fn add_to_all_candidate_sets < ' pat > ( & mut self ,
396
+ candidate : & Candidate < ' pat , ' tcx > ,
397
+ resulting_candidates : & mut Vec < Vec < Candidate < ' pat , ' tcx > > > ) {
398
+ for resulting_candidate in resulting_candidates {
399
+ resulting_candidate. push ( candidate. clone ( ) ) ;
400
+ }
401
+ }
477
402
478
- PatternKind :: Constant { value : Literal :: Value { ref value } }
479
- if is_switch_ty ( match_pair. pattern . ty ) => {
480
- match * test_kind {
481
- TestKind :: SwitchInt { switch_ty : _, options : _, ref indices } => {
482
- let index = indices[ value] ;
483
- if index == test_outcome {
484
- Some ( vec ! [ ] ) // this value, nothing left to test
485
- } else {
486
- None // some other value, candidate is inapplicable
487
- }
488
- }
403
+ fn candidate_after_variant_switch < ' pat > ( & mut self ,
404
+ match_pair_index : usize ,
405
+ adt_def : ty:: AdtDef < ' tcx > ,
406
+ variant_index : usize ,
407
+ subpatterns : & ' pat [ FieldPattern < ' tcx > ] ,
408
+ candidate : & Candidate < ' pat , ' tcx > )
409
+ -> Candidate < ' pat , ' tcx > {
410
+ let match_pair = & candidate. match_pairs [ match_pair_index] ;
411
+
412
+ // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
413
+ // we want to create a set of derived match-patterns like
414
+ // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
415
+ let elem = ProjectionElem :: Downcast ( adt_def, variant_index) ;
416
+ let downcast_lvalue = match_pair. lvalue . clone ( ) . elem ( elem) ; // `(x as Variant)`
417
+ let consequent_match_pairs =
418
+ subpatterns. iter ( )
419
+ . map ( |subpattern| {
420
+ // e.g., `(x as Variant).0`
421
+ let lvalue = downcast_lvalue. clone ( ) . field ( subpattern. field ) ;
422
+ // e.g., `(x as Variant).0 @ P1`
423
+ MatchPair :: new ( lvalue, & subpattern. pattern )
424
+ } ) ;
489
425
490
- _ => {
491
- self . hir . span_bug (
492
- match_pair. pattern . span ,
493
- & format ! ( "did a switch-int, but value {:?} not found in cases" ,
494
- value) ) ;
495
- }
496
- }
497
- }
426
+ // In addition, we need all the other match pairs from the old candidate.
427
+ let other_match_pairs =
428
+ candidate. match_pairs . iter ( )
429
+ . enumerate ( )
430
+ . filter ( |& ( index, _) | index != match_pair_index)
431
+ . map ( |( _, mp) | mp. clone ( ) ) ;
498
432
499
- PatternKind :: Constant { .. } |
500
- PatternKind :: Range { .. } |
501
- PatternKind :: Slice { .. } => {
502
- if test_outcome == 0 {
503
- Some ( vec ! [ ] )
504
- } else {
505
- None
506
- }
507
- }
433
+ let all_match_pairs = consequent_match_pairs. chain ( other_match_pairs) . collect ( ) ;
508
434
509
- PatternKind :: Array { .. } |
510
- PatternKind :: Wild |
511
- PatternKind :: Binding { .. } |
512
- PatternKind :: Leaf { .. } |
513
- PatternKind :: Deref { .. } => {
514
- self . error_simplifyable ( match_pair)
515
- }
435
+ Candidate {
436
+ match_pairs : all_match_pairs,
437
+ bindings : candidate. bindings . clone ( ) ,
438
+ guard : candidate. guard . clone ( ) ,
439
+ arm_index : candidate. arm_index ,
516
440
}
517
441
}
518
442
0 commit comments