use build::Builder;
use build::matches::{Candidate, MatchPair, Test, TestKind};
use hair::*;
+use hair::pattern::compare_const_vals;
use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::fx::FxHashMap;
use rustc::ty::{self, Ty};
PatternKind::Variant { .. } => {
panic!("you should have called add_variants_to_switch instead!");
}
- PatternKind::Range { .. } |
+ PatternKind::Range { ty, lo, hi, end } => {
+ indices
+ .keys()
+ .all(|value| {
+ !self
+ .const_range_contains(ty, lo, hi, end, value)
+ .unwrap_or(true)
+ })
+ }
PatternKind::Slice { .. } |
PatternKind::Array { .. } |
PatternKind::Wild |
resulting_candidates[index].push(new_candidate);
true
}
+
+ (&TestKind::SwitchInt { switch_ty: _, ref options, ref indices },
+ &PatternKind::Range { ty, lo, hi, end }) => {
+ let not_contained = indices
+ .keys()
+ .all(|value| {
+ !self
+ .const_range_contains(ty, lo, hi, end, value)
+ .unwrap_or(true)
+ });
+
+ if not_contained {
+ // No values are contained in the pattern range,
+ // so the pattern can be matched only if this test fails.
+ let otherwise = options.len();
+ resulting_candidates[otherwise].push(candidate.clone());
+ true
+ } else {
+ false
+ }
+ }
+
(&TestKind::SwitchInt { .. }, _) => false,
}
}
+ (&TestKind::Range {
+ lo: test_lo, hi: test_hi, ty: test_ty, end: test_end,
+ }, &PatternKind::Range {
+ lo: pat_lo, hi: pat_hi, ty: _, end: pat_end,
+ }) => {
+ if (test_lo, test_hi, test_end) == (pat_lo, pat_hi, pat_end) {
+ resulting_candidates[0]
+ .push(self.candidate_without_match_pair(
+ match_pair_index,
+ candidate,
+ ));
+ return true;
+ }
+
+ let no_overlap = (|| {
+ use std::cmp::Ordering::*;
+ use rustc::hir::RangeEnd::*;
+
+ let param_env = ty::ParamEnv::empty().and(test_ty);
+ let tcx = self.hir.tcx();
+
+ let lo = compare_const_vals(tcx, test_lo, pat_hi, param_env)?;
+ let hi = compare_const_vals(tcx, test_hi, pat_lo, param_env)?;
+
+ match (test_end, pat_end, lo, hi) {
+ // pat < test
+ (_, _, Greater, _) |
+ (_, Excluded, Equal, _) |
+ // pat > test
+ (_, _, _, Less) |
+ (Excluded, _, _, Equal) => Some(true),
+ _ => Some(false),
+ }
+ })();
+
+ if no_overlap == Some(true) {
+ // Testing range does not overlap with pattern range,
+ // so the pattern can be matched only if this test fails.
+ resulting_candidates[1].push(candidate.clone());
+ true
+ } else {
+ false
+ }
+ }
+
+ (&TestKind::Range {
+ lo, hi, ty, end
+ }, &PatternKind::Constant {
+ ref value
+ }) => {
+ if self.const_range_contains(ty, lo, hi, end, value) == Some(false) {
+ // `value` is not contained in the testing range,
+ // so `value` can be matched only if this test fails.
+ resulting_candidates[1].push(candidate.clone());
+ true
+ } else {
+ false
+ }
+ }
+
+ (&TestKind::Range { .. }, _) => false,
+
+
(&TestKind::Eq { .. }, _) |
- (&TestKind::Range { .. }, _) |
(&TestKind::Len { .. }, _) => {
// These are all binary tests.
//
"simplifyable pattern found: {:?}",
match_pair.pattern)
}
+
+ fn const_range_contains(
+ &self,
+ ty: Ty<'tcx>,
+ lo: &'tcx ty::Const<'tcx>,
+ hi: &'tcx ty::Const<'tcx>,
+ end: RangeEnd,
+ value: &'tcx ty::Const<'tcx>,
+ ) -> Option<bool> {
+ use std::cmp::Ordering::*;
+
+ let param_env = ty::ParamEnv::empty().and(ty);
+ let tcx = self.hir.tcx();
+
+ let a = compare_const_vals(tcx, lo, value, param_env)?;
+ let b = compare_const_vals(tcx, value, hi, param_env)?;
+
+ match (b, end) {
+ (Less, _) |
+ (Equal, RangeEnd::Included) if a != Greater => Some(true),
+ _ => Some(false),
+ }
+ }
}
fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
-use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty};
+use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift};
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::layout::VariantIdx;
use rustc::hir::{self, PatKind, RangeEnd};
}
}
-pub fn compare_const_vals<'a, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn compare_const_vals<'a, 'gcx, 'tcx>(
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
a: &'tcx ty::Const<'tcx>,
b: &'tcx ty::Const<'tcx>,
ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
return fallback();
}
+ let tcx = tcx.global_tcx();
+ let (a, b, ty) = (a, b, ty).lift_to_tcx(tcx).unwrap();
+
// FIXME: This should use assert_bits(ty) instead of use_bits
// but triggers possibly bugs due to mismatching of arrays and slices
if let (Some(a), Some(b)) = (a.to_bits(tcx, ty), b.to_bits(tcx, ty)) {
--- /dev/null
+#![feature(exclusive_range_pattern)]
+
+// run-pass
+
+fn main() {
+ let incl_range = |x, b| {
+ match x {
+ 0..=5 if b => 0,
+ 5..=10 if b => 1,
+ 1..=4 if !b => 2,
+ _ => 3,
+ }
+ };
+ assert_eq!(incl_range(3, false), 2);
+ assert_eq!(incl_range(3, true), 0);
+ assert_eq!(incl_range(5, false), 3);
+ assert_eq!(incl_range(5, true), 0);
+
+ let excl_range = |x, b| {
+ match x {
+ 0..5 if b => 0,
+ 5..10 if b => 1,
+ 1..4 if !b => 2,
+ _ => 3,
+ }
+ };
+ assert_eq!(excl_range(3, false), 2);
+ assert_eq!(excl_range(3, true), 0);
+ assert_eq!(excl_range(5, false), 3);
+ assert_eq!(excl_range(5, true), 1);
+
+ let incl_range_vs_const = |x, b| {
+ match x {
+ 0..=5 if b => 0,
+ 7 => 1,
+ 3 => 2,
+ _ => 3,
+ }
+ };
+ assert_eq!(incl_range_vs_const(5, false), 3);
+ assert_eq!(incl_range_vs_const(5, true), 0);
+ assert_eq!(incl_range_vs_const(3, false), 2);
+ assert_eq!(incl_range_vs_const(3, true), 0);
+ assert_eq!(incl_range_vs_const(7, false), 1);
+ assert_eq!(incl_range_vs_const(7, true), 1);
+
+ let excl_range_vs_const = |x, b| {
+ match x {
+ 0..5 if b => 0,
+ 7 => 1,
+ 3 => 2,
+ _ => 3,
+ }
+ };
+ assert_eq!(excl_range_vs_const(5, false), 3);
+ assert_eq!(excl_range_vs_const(5, true), 3);
+ assert_eq!(excl_range_vs_const(3, false), 2);
+ assert_eq!(excl_range_vs_const(3, true), 0);
+ assert_eq!(excl_range_vs_const(7, false), 1);
+ assert_eq!(excl_range_vs_const(7, true), 1);
+
+ let const_vs_incl_range = |x, b| {
+ match x {
+ 3 if b => 0,
+ 5..=7 => 2,
+ 1..=4 => 1,
+ _ => 3,
+ }
+ };
+ assert_eq!(const_vs_incl_range(3, false), 1);
+ assert_eq!(const_vs_incl_range(3, true), 0);
+
+ let const_vs_excl_range = |x, b| {
+ match x {
+ 3 if b => 0,
+ 5..7 => 2,
+ 1..4 => 1,
+ _ => 3,
+ }
+ };
+ assert_eq!(const_vs_excl_range(3, false), 1);
+ assert_eq!(const_vs_excl_range(3, true), 0);
+}