|
18 | 18 | use build::Builder;
|
19 | 19 | use build::matches::{Candidate, MatchPair, Test, TestKind};
|
20 | 20 | use hair::*;
|
| 21 | +use hair::pattern::compare_const_vals; |
21 | 22 | use rustc_data_structures::bit_set::BitSet;
|
22 | 23 | use rustc_data_structures::fx::FxHashMap;
|
23 | 24 | use rustc::ty::{self, Ty};
|
@@ -136,7 +137,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
136 | 137 | PatternKind::Variant { .. } => {
|
137 | 138 | panic!("you should have called add_variants_to_switch instead!");
|
138 | 139 | }
|
139 |
| - PatternKind::Range { .. } | |
| 140 | + PatternKind::Range { ty, lo, hi, end } => { |
| 141 | + indices |
| 142 | + .keys() |
| 143 | + .all(|value| { |
| 144 | + !self |
| 145 | + .const_range_contains(ty, lo, hi, end, value) |
| 146 | + .unwrap_or(true) |
| 147 | + }) |
| 148 | + } |
140 | 149 | PatternKind::Slice { .. } |
|
141 | 150 | PatternKind::Array { .. } |
|
142 | 151 | PatternKind::Wild |
|
@@ -529,6 +538,28 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
529 | 538 | resulting_candidates[index].push(new_candidate);
|
530 | 539 | true
|
531 | 540 | }
|
| 541 | + |
| 542 | + (&TestKind::SwitchInt { switch_ty: _, ref options, ref indices }, |
| 543 | + &PatternKind::Range { ty, lo, hi, end }) => { |
| 544 | + let not_contained = indices |
| 545 | + .keys() |
| 546 | + .all(|value| { |
| 547 | + !self |
| 548 | + .const_range_contains(ty, lo, hi, end, value) |
| 549 | + .unwrap_or(true) |
| 550 | + }); |
| 551 | + |
| 552 | + if not_contained { |
| 553 | + // No values are contained in the pattern range, |
| 554 | + // so the pattern can be matched only if this test fails. |
| 555 | + let otherwise = options.len(); |
| 556 | + resulting_candidates[otherwise].push(candidate.clone()); |
| 557 | + true |
| 558 | + } else { |
| 559 | + false |
| 560 | + } |
| 561 | + } |
| 562 | + |
532 | 563 | (&TestKind::SwitchInt { .. }, _) => false,
|
533 | 564 |
|
534 | 565 |
|
@@ -607,8 +638,70 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
607 | 638 | }
|
608 | 639 | }
|
609 | 640 |
|
| 641 | + (&TestKind::Range { |
| 642 | + lo: test_lo, hi: test_hi, ty: test_ty, end: test_end, |
| 643 | + }, &PatternKind::Range { |
| 644 | + lo: pat_lo, hi: pat_hi, ty: _, end: pat_end, |
| 645 | + }) => { |
| 646 | + if (test_lo, test_hi, test_end) == (pat_lo, pat_hi, pat_end) { |
| 647 | + resulting_candidates[0] |
| 648 | + .push(self.candidate_without_match_pair( |
| 649 | + match_pair_index, |
| 650 | + candidate, |
| 651 | + )); |
| 652 | + return true; |
| 653 | + } |
| 654 | + |
| 655 | + let no_overlap = (|| { |
| 656 | + use std::cmp::Ordering::*; |
| 657 | + use rustc::hir::RangeEnd::*; |
| 658 | + |
| 659 | + let param_env = ty::ParamEnv::empty().and(test_ty); |
| 660 | + let tcx = self.hir.tcx(); |
| 661 | + |
| 662 | + let lo = compare_const_vals(tcx, test_lo, pat_hi, param_env)?; |
| 663 | + let hi = compare_const_vals(tcx, test_hi, pat_lo, param_env)?; |
| 664 | + |
| 665 | + match (test_end, pat_end, lo, hi) { |
| 666 | + // pat < test |
| 667 | + (_, _, Greater, _) | |
| 668 | + (_, Excluded, Equal, _) | |
| 669 | + // pat > test |
| 670 | + (_, _, _, Less) | |
| 671 | + (Excluded, _, _, Equal) => Some(true), |
| 672 | + _ => Some(false), |
| 673 | + } |
| 674 | + })(); |
| 675 | + |
| 676 | + if no_overlap == Some(true) { |
| 677 | + // Testing range does not overlap with pattern range, |
| 678 | + // so the pattern can be matched only if this test fails. |
| 679 | + resulting_candidates[1].push(candidate.clone()); |
| 680 | + true |
| 681 | + } else { |
| 682 | + false |
| 683 | + } |
| 684 | + } |
| 685 | + |
| 686 | + (&TestKind::Range { |
| 687 | + lo, hi, ty, end |
| 688 | + }, &PatternKind::Constant { |
| 689 | + ref value |
| 690 | + }) => { |
| 691 | + if self.const_range_contains(ty, lo, hi, end, value) == Some(false) { |
| 692 | + // `value` is not contained in the testing range, |
| 693 | + // so `value` can be matched only if this test fails. |
| 694 | + resulting_candidates[1].push(candidate.clone()); |
| 695 | + true |
| 696 | + } else { |
| 697 | + false |
| 698 | + } |
| 699 | + } |
| 700 | + |
| 701 | + (&TestKind::Range { .. }, _) => false, |
| 702 | + |
| 703 | + |
610 | 704 | (&TestKind::Eq { .. }, _) |
|
611 |
| - (&TestKind::Range { .. }, _) | |
612 | 705 | (&TestKind::Len { .. }, _) => {
|
613 | 706 | // These are all binary tests.
|
614 | 707 | //
|
@@ -719,6 +812,29 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
719 | 812 | "simplifyable pattern found: {:?}",
|
720 | 813 | match_pair.pattern)
|
721 | 814 | }
|
| 815 | + |
| 816 | + fn const_range_contains( |
| 817 | + &self, |
| 818 | + ty: Ty<'tcx>, |
| 819 | + lo: &'tcx ty::Const<'tcx>, |
| 820 | + hi: &'tcx ty::Const<'tcx>, |
| 821 | + end: RangeEnd, |
| 822 | + value: &'tcx ty::Const<'tcx>, |
| 823 | + ) -> Option<bool> { |
| 824 | + use std::cmp::Ordering::*; |
| 825 | + |
| 826 | + let param_env = ty::ParamEnv::empty().and(ty); |
| 827 | + let tcx = self.hir.tcx(); |
| 828 | + |
| 829 | + let a = compare_const_vals(tcx, lo, value, param_env)?; |
| 830 | + let b = compare_const_vals(tcx, value, hi, param_env)?; |
| 831 | + |
| 832 | + match (b, end) { |
| 833 | + (Less, _) | |
| 834 | + (Equal, RangeEnd::Included) if a != Greater => Some(true), |
| 835 | + _ => Some(false), |
| 836 | + } |
| 837 | + } |
722 | 838 | }
|
723 | 839 |
|
724 | 840 | fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
|
|
0 commit comments