3 // After candidates have been simplified, the only match pairs that
4 // remain are those that require some sort of test. The functions here
5 // identify what tests are needed, perform the tests, and then filter
6 // the candidates based on the result.
8 use crate::build::Builder;
9 use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
11 use crate::hair::pattern::compare_const_vals;
12 use rustc_data_structures::bit_set::BitSet;
13 use rustc_data_structures::fx::FxHashMap;
14 use rustc::ty::{self, Ty};
15 use rustc::ty::util::IntTypeExt;
16 use rustc::ty::layout::VariantIdx;
18 use rustc::hir::{RangeEnd, Mutability};
20 use std::cmp::Ordering;
22 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
23 /// Identifies what test is needed to decide if `match_pair` is applicable.
25 /// It is a bug to call this with a simplifiable pattern.
26 pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
27 match *match_pair.pattern.kind {
28 PatternKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => {
30 span: match_pair.pattern.span,
31 kind: TestKind::Switch {
32 adt_def: adt_def.clone(),
33 variants: BitSet::new_empty(adt_def.variants.len()),
38 PatternKind::Constant { .. }
39 if is_switch_ty(match_pair.pattern.ty) => {
40 // for integers, we use a SwitchInt match, which allows
41 // us to handle more cases
43 span: match_pair.pattern.span,
44 kind: TestKind::SwitchInt {
45 switch_ty: match_pair.pattern.ty,
47 // these maps are empty to start; cases are
48 // added below in add_cases_to_switch
50 indices: Default::default(),
55 PatternKind::Constant { value } => {
57 span: match_pair.pattern.span,
60 ty: match_pair.pattern.ty.clone()
65 PatternKind::Range(range) => {
66 assert!(range.ty == match_pair.pattern.ty);
68 span: match_pair.pattern.span,
69 kind: TestKind::Range(range),
73 PatternKind::Slice { ref prefix, ref slice, ref suffix }
74 if !match_pair.slice_len_checked => {
75 let len = prefix.len() + suffix.len();
76 let op = if slice.is_some() {
82 span: match_pair.pattern.span,
83 kind: TestKind::Len { len: len as u64, op: op },
87 PatternKind::AscribeUserType { .. } |
88 PatternKind::Array { .. } |
89 PatternKind::Slice { .. } |
91 PatternKind::Binding { .. } |
92 PatternKind::Leaf { .. } |
93 PatternKind::Deref { .. } => {
94 self.error_simplifyable(match_pair)
99 pub fn add_cases_to_switch<'pat>(&mut self,
100 test_place: &Place<'tcx>,
101 candidate: &Candidate<'pat, 'tcx>,
103 options: &mut Vec<u128>,
104 indices: &mut FxHashMap<ty::Const<'tcx>, usize>)
107 let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
108 Some(match_pair) => match_pair,
109 _ => { return false; }
112 match *match_pair.pattern.kind {
113 PatternKind::Constant { value } => {
114 let switch_ty = ty::ParamEnv::empty().and(switch_ty);
117 options.push(value.unwrap_bits(self.hir.tcx(), switch_ty));
122 PatternKind::Variant { .. } => {
123 panic!("you should have called add_variants_to_switch instead!");
125 PatternKind::Range(range) => {
126 // Check that none of the switch values are in the range.
127 self.values_not_contained_in_range(range, indices)
130 PatternKind::Slice { .. } |
131 PatternKind::Array { .. } |
133 PatternKind::Binding { .. } |
134 PatternKind::AscribeUserType { .. } |
135 PatternKind::Leaf { .. } |
136 PatternKind::Deref { .. } => {
137 // don't know how to add these patterns to a switch
143 pub fn add_variants_to_switch<'pat>(&mut self,
144 test_place: &Place<'tcx>,
145 candidate: &Candidate<'pat, 'tcx>,
146 variants: &mut BitSet<VariantIdx>)
149 let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
150 Some(match_pair) => match_pair,
151 _ => { return false; }
154 match *match_pair.pattern.kind {
155 PatternKind::Variant { adt_def: _ , variant_index, .. } => {
156 // We have a pattern testing for variant `variant_index`
157 // set the corresponding index to true
158 variants.insert(variant_index);
162 // don't know how to add these patterns to a switch
168 /// Generates the code to perform a test.
169 pub fn perform_test(&mut self,
174 debug!("perform_test({:?}, {:?}: {:?}, {:?})",
177 place.ty(&self.local_decls, self.hir.tcx()),
179 let source_info = self.source_info(test.span);
181 TestKind::Switch { adt_def, ref variants } => {
182 // Variants is a BitVec of indexes into adt_def.variants.
183 let num_enum_variants = adt_def.variants.len();
184 let used_variants = variants.count();
185 let mut otherwise_block = None;
186 let mut target_blocks = Vec::with_capacity(num_enum_variants);
187 let mut targets = Vec::with_capacity(used_variants + 1);
188 let mut values = Vec::with_capacity(used_variants);
189 let tcx = self.hir.tcx();
190 for (idx, discr) in adt_def.discriminants(tcx) {
191 target_blocks.push(if variants.contains(idx) {
192 values.push(discr.val);
193 let block = self.cfg.start_new_block();
198 .get_or_insert_with(|| self.cfg.start_new_block())
203 .unwrap_or_else(|| self.unreachable_block()),
205 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
206 num_enum_variants, values, variants);
207 let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
208 let discr = self.temp(discr_ty, test.span);
209 self.cfg.push_assign(block, source_info, &discr,
210 Rvalue::Discriminant(place.clone()));
211 assert_eq!(values.len() + 1, targets.len());
212 self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
213 discr: Operand::Move(discr),
215 values: From::from(values),
221 TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
222 let (ret, terminator) = if switch_ty.sty == ty::Bool {
223 assert!(options.len() > 0 && options.len() <= 2);
224 let (true_bb, false_bb) = (self.cfg.start_new_block(),
225 self.cfg.start_new_block());
226 let ret = match options[0] {
227 1 => vec![true_bb, false_bb],
228 0 => vec![false_bb, true_bb],
229 v => span_bug!(test.span, "expected boolean value but got {:?}", v)
231 (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()),
234 // The switch may be inexhaustive so we
235 // add a catch all block
236 let otherwise = self.cfg.start_new_block();
237 let targets: Vec<_> =
239 .map(|_| self.cfg.start_new_block())
240 .chain(Some(otherwise))
242 (targets.clone(), TerminatorKind::SwitchInt {
243 discr: Operand::Copy(place.clone()),
245 values: options.clone().into(),
249 self.cfg.terminate(block, source_info, terminator);
253 TestKind::Eq { value, mut ty } => {
254 let val = Operand::Copy(place.clone());
255 let mut expect = self.literal_operand(test.span, ty, value);
256 // Use PartialEq::eq instead of BinOp::Eq
257 // (the binop can only handle primitives)
258 let fail = self.cfg.start_new_block();
260 // If we're using b"..." as a pattern, we need to insert an
261 // unsizing coercion, as the byte string has the type &[u8; N].
263 // We want to do this even when the scrutinee is a reference to an
264 // array, so we can call `<[u8]>::eq` rather than having to find an
266 let unsize = |ty: Ty<'tcx>| match ty.sty {
267 ty::Ref(region, rty, _) => match rty.sty {
268 ty::Array(inner_ty, n) => Some((region, inner_ty, n)),
273 let opt_ref_ty = unsize(ty);
274 let opt_ref_test_ty = unsize(value.ty);
275 let mut place = place.clone();
276 match (opt_ref_ty, opt_ref_test_ty) {
277 // nothing to do, neither is an array
279 (Some((region, elem_ty, _)), _) |
280 (None, Some((region, elem_ty, _))) => {
281 let tcx = self.hir.tcx();
283 ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
284 if opt_ref_ty.is_some() {
285 place = self.temp(ty, test.span);
286 self.cfg.push_assign(block, source_info, &place,
287 Rvalue::Cast(CastKind::Unsize, val, ty));
289 if opt_ref_test_ty.is_some() {
290 let array = self.literal_operand(
296 let slice = self.temp(ty, test.span);
297 self.cfg.push_assign(block, source_info, &slice,
298 Rvalue::Cast(CastKind::Unsize, array, ty));
299 expect = Operand::Move(slice);
303 let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap();
304 let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]);
305 let method = self.hir.tcx().mk_lazy_const(ty::LazyConst::Evaluated(method));
307 let re_erased = self.hir.tcx().types.re_erased;
308 // take the argument by reference
309 let tam = ty::TypeAndMut {
311 mutbl: Mutability::MutImmutable,
313 let ref_ty = self.hir.tcx().mk_ref(re_erased, tam);
315 // let lhs_ref_place = &lhs;
316 let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, place);
317 let lhs_ref_place = self.temp(ref_ty, test.span);
318 self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue);
319 let val = Operand::Move(lhs_ref_place);
321 // let rhs_place = rhs;
322 let rhs_place = self.temp(ty, test.span);
323 self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect));
325 // let rhs_ref_place = &rhs_place;
326 let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, rhs_place);
327 let rhs_ref_place = self.temp(ref_ty, test.span);
328 self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue);
329 let expect = Operand::Move(rhs_ref_place);
331 let bool_ty = self.hir.bool_ty();
332 let eq_result = self.temp(bool_ty, test.span);
333 let eq_block = self.cfg.start_new_block();
334 let cleanup = self.diverge_cleanup();
335 self.cfg.terminate(block, source_info, TerminatorKind::Call {
336 func: Operand::Constant(box Constant {
340 // FIXME(#54571): This constant comes from user
341 // input (a constant in a pattern). Are
342 // there forms where users can add type
343 // annotations here? For example, an
344 // associated constant? Need to
350 args: vec![val, expect],
351 destination: Some((eq_result.clone(), eq_block)),
352 cleanup: Some(cleanup),
353 from_hir_call: false,
357 let block = self.cfg.start_new_block();
358 self.cfg.terminate(eq_block, source_info,
359 TerminatorKind::if_(self.hir.tcx(),
360 Operand::Move(eq_result),
364 let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
369 TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => {
370 // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
371 let lo = self.literal_operand(test.span, ty.clone(), lo.clone());
372 let hi = self.literal_operand(test.span, ty.clone(), hi.clone());
373 let val = Operand::Copy(place.clone());
375 let fail = self.cfg.start_new_block();
376 let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone());
377 let block = match *end {
378 RangeEnd::Included => self.compare(block, fail, test.span, BinOp::Le, val, hi),
379 RangeEnd::Excluded => self.compare(block, fail, test.span, BinOp::Lt, val, hi),
385 TestKind::Len { len, op } => {
386 let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty());
387 let (actual, result) = (self.temp(usize_ty, test.span),
388 self.temp(bool_ty, test.span));
390 // actual = len(place)
391 self.cfg.push_assign(block, source_info,
392 &actual, Rvalue::Len(place.clone()));
395 let expected = self.push_usize(block, source_info, len);
397 // result = actual == expected OR result = actual < expected
398 self.cfg.push_assign(block, source_info, &result,
400 Operand::Move(actual),
401 Operand::Move(expected)));
403 // branch based on result
404 let (false_bb, true_bb) = (self.cfg.start_new_block(),
405 self.cfg.start_new_block());
406 self.cfg.terminate(block, source_info,
407 TerminatorKind::if_(self.hir.tcx(), Operand::Move(result),
409 vec![true_bb, false_bb]
414 fn compare(&mut self,
416 fail_block: BasicBlock,
420 right: Operand<'tcx>) -> BasicBlock {
421 let bool_ty = self.hir.bool_ty();
422 let result = self.temp(bool_ty, span);
424 // result = op(left, right)
425 let source_info = self.source_info(span);
426 self.cfg.push_assign(block, source_info, &result,
427 Rvalue::BinaryOp(op, left, right));
429 // branch based on result
430 let target_block = self.cfg.start_new_block();
431 self.cfg.terminate(block, source_info,
432 TerminatorKind::if_(self.hir.tcx(), Operand::Move(result),
433 target_block, fail_block));
437 /// Given that we are performing `test` against `test_place`,
438 /// this job sorts out what the status of `candidate` will be
439 /// after the test. The `resulting_candidates` vector stores, for
440 /// each possible outcome of `test`, a vector of the candidates
441 /// that will result. This fn should add a (possibly modified)
442 /// clone of candidate into `resulting_candidates` wherever
445 /// So, for example, if this candidate is `x @ Some(P0)` and the
446 /// test is a variant test, then we would add `(x as Option).0 @
447 /// P0` to the `resulting_candidates` entry corresponding to the
450 /// However, in some cases, the test may just not be relevant to
451 /// candidate. For example, suppose we are testing whether `foo.x == 22`,
452 /// but in one match arm we have `Foo { x: _, ... }`... in that case,
453 /// the test for what value `x` has has no particular relevance
454 /// to this candidate. In such cases, this function just returns false
455 /// without doing anything. This is used by the overall `match_candidates`
456 /// algorithm to structure the match as a whole. See `match_candidates` for
459 /// FIXME(#29623). In some cases, we have some tricky choices to
460 /// make. for example, if we are testing that `x == 22`, but the
461 /// candidate is `x @ 13..55`, what should we do? In the event
462 /// that the test is true, we know that the candidate applies, but
463 /// in the event of false, we don't know that it *doesn't*
464 /// apply. For now, we return false, indicate that the test does
465 /// not apply to this candidate, but it might be we can get
466 /// tighter match code if we do something a bit different.
467 pub fn sort_candidate<'pat>(&mut self,
468 test_place: &Place<'tcx>,
470 candidate: &Candidate<'pat, 'tcx>,
471 resulting_candidates: &mut [Vec<Candidate<'pat, 'tcx>>])
473 // Find the match_pair for this place (if any). At present,
474 // afaik, there can be at most one. (In the future, if we
475 // adopted a more general `@` operator, there might be more
476 // than one, but it'd be very unusual to have two sides that
477 // both require tests; you'd expect one side to be simplified
479 let tested_match_pair = candidate.match_pairs.iter()
481 .find(|&(_, mp)| mp.place == *test_place);
482 let (match_pair_index, match_pair) = match tested_match_pair {
485 // We are not testing this place. Therefore, this
486 // candidate applies to ALL outcomes.
491 match (&test.kind, &*match_pair.pattern.kind) {
492 // If we are performing a variant switch, then this
493 // informs variant patterns, but nothing else.
494 (&TestKind::Switch { adt_def: tested_adt_def, .. },
495 &PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. }) => {
496 assert_eq!(adt_def, tested_adt_def);
498 self.candidate_after_variant_switch(match_pair_index,
503 resulting_candidates[variant_index.as_usize()].push(new_candidate);
506 (&TestKind::Switch { .. }, _) => false,
508 // If we are performing a switch over integers, then this informs integer
509 // equality, but nothing else.
511 // FIXME(#29623) we could use PatternKind::Range to rule
512 // things out here, in some cases.
513 (&TestKind::SwitchInt { switch_ty: _, options: _, ref indices },
514 &PatternKind::Constant { ref value })
515 if is_switch_ty(match_pair.pattern.ty) => {
516 let index = indices[value];
517 let new_candidate = self.candidate_without_match_pair(match_pair_index,
519 resulting_candidates[index].push(new_candidate);
523 (&TestKind::SwitchInt { switch_ty: _, ref options, ref indices },
524 &PatternKind::Range(range)) => {
525 let not_contained = self
526 .values_not_contained_in_range(range, indices)
530 // No switch values are contained in the pattern range,
531 // so the pattern can be matched only if this test fails.
532 let otherwise = options.len();
533 resulting_candidates[otherwise].push(candidate.clone());
540 (&TestKind::SwitchInt { .. }, _) => false,
543 (&TestKind::Len { len: test_len, op: BinOp::Eq },
544 &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
545 let pat_len = (prefix.len() + suffix.len()) as u64;
546 match (test_len.cmp(&pat_len), slice) {
547 (Ordering::Equal, &None) => {
548 // on true, min_len = len = $actual_length,
549 // on false, len != $actual_length
550 resulting_candidates[0].push(
551 self.candidate_after_slice_test(match_pair_index,
559 (Ordering::Less, _) => {
560 // test_len < pat_len. If $actual_len = test_len,
561 // then $actual_len < pat_len and we don't have
563 resulting_candidates[1].push(candidate.clone());
566 (Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => {
567 // This can match both if $actual_len = test_len >= pat_len,
568 // and if $actual_len > test_len. We can't advance.
571 (Ordering::Greater, &None) => {
572 // test_len != pat_len, so if $actual_len = test_len, then
573 // $actual_len != pat_len.
574 resulting_candidates[1].push(candidate.clone());
580 (&TestKind::Len { len: test_len, op: BinOp::Ge },
581 &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
582 // the test is `$actual_len >= test_len`
583 let pat_len = (prefix.len() + suffix.len()) as u64;
584 match (test_len.cmp(&pat_len), slice) {
585 (Ordering::Equal, &Some(_)) => {
586 // $actual_len >= test_len = pat_len,
588 resulting_candidates[0].push(
589 self.candidate_after_slice_test(match_pair_index,
597 (Ordering::Less, _) | (Ordering::Equal, &None) => {
598 // test_len <= pat_len. If $actual_len < test_len,
599 // then it is also < pat_len, so the test passing is
600 // necessary (but insufficient).
601 resulting_candidates[0].push(candidate.clone());
604 (Ordering::Greater, &None) => {
605 // test_len > pat_len. If $actual_len >= test_len > pat_len,
606 // then we know we won't have a match.
607 resulting_candidates[1].push(candidate.clone());
610 (Ordering::Greater, &Some(_)) => {
611 // test_len < pat_len, and is therefore less
612 // strict. This can still go both ways.
618 (&TestKind::Range(test),
619 &PatternKind::Range(pat)) => {
621 resulting_candidates[0]
622 .push(self.candidate_without_match_pair(
629 let no_overlap = (|| {
630 use std::cmp::Ordering::*;
631 use rustc::hir::RangeEnd::*;
633 let param_env = ty::ParamEnv::empty().and(test.ty);
634 let tcx = self.hir.tcx();
636 let lo = compare_const_vals(tcx, test.lo, pat.hi, param_env)?;
637 let hi = compare_const_vals(tcx, test.hi, pat.lo, param_env)?;
639 match (test.end, pat.end, lo, hi) {
642 (_, Excluded, Equal, _) |
645 (Excluded, _, _, Equal) => Some(true),
650 if no_overlap == Some(true) {
651 // Testing range does not overlap with pattern range,
652 // so the pattern can be matched only if this test fails.
653 resulting_candidates[1].push(candidate.clone());
660 (&TestKind::Range(range), &PatternKind::Constant { value }) => {
661 if self.const_range_contains(range, value) == Some(false) {
662 // `value` is not contained in the testing range,
663 // so `value` can be matched only if this test fails.
664 resulting_candidates[1].push(candidate.clone());
671 (&TestKind::Range { .. }, _) => false,
674 (&TestKind::Eq { .. }, _) |
675 (&TestKind::Len { .. }, _) => {
676 // These are all binary tests.
678 // FIXME(#29623) we can be more clever here
679 let pattern_test = self.test(&match_pair);
680 if pattern_test.kind == test.kind {
681 let new_candidate = self.candidate_without_match_pair(match_pair_index,
683 resulting_candidates[0].push(new_candidate);
692 fn candidate_without_match_pair<'pat>(&mut self,
693 match_pair_index: usize,
694 candidate: &Candidate<'pat, 'tcx>)
695 -> Candidate<'pat, 'tcx> {
696 let other_match_pairs =
697 candidate.match_pairs.iter()
699 .filter(|&(index, _)| index != match_pair_index)
700 .map(|(_, mp)| mp.clone())
703 span: candidate.span,
704 match_pairs: other_match_pairs,
705 bindings: candidate.bindings.clone(),
706 ascriptions: candidate.ascriptions.clone(),
707 guard: candidate.guard.clone(),
708 arm_index: candidate.arm_index,
709 pat_index: candidate.pat_index,
710 pre_binding_block: candidate.pre_binding_block,
711 next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block,
715 fn candidate_after_slice_test<'pat>(&mut self,
716 match_pair_index: usize,
717 candidate: &Candidate<'pat, 'tcx>,
718 prefix: &'pat [Pattern<'tcx>],
719 opt_slice: Option<&'pat Pattern<'tcx>>,
720 suffix: &'pat [Pattern<'tcx>])
721 -> Candidate<'pat, 'tcx> {
722 let mut new_candidate =
723 self.candidate_without_match_pair(match_pair_index, candidate);
724 self.prefix_slice_suffix(
725 &mut new_candidate.match_pairs,
726 &candidate.match_pairs[match_pair_index].place,
734 fn candidate_after_variant_switch<'pat>(&mut self,
735 match_pair_index: usize,
736 adt_def: &'tcx ty::AdtDef,
737 variant_index: VariantIdx,
738 subpatterns: &'pat [FieldPattern<'tcx>],
739 candidate: &Candidate<'pat, 'tcx>)
740 -> Candidate<'pat, 'tcx> {
741 let match_pair = &candidate.match_pairs[match_pair_index];
743 // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
744 // we want to create a set of derived match-patterns like
745 // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
746 let elem = ProjectionElem::Downcast(adt_def, variant_index);
747 let downcast_place = match_pair.place.clone().elem(elem); // `(x as Variant)`
748 let consequent_match_pairs =
751 // e.g., `(x as Variant).0`
752 let place = downcast_place.clone().field(subpattern.field,
753 subpattern.pattern.ty);
754 // e.g., `(x as Variant).0 @ P1`
755 MatchPair::new(place, &subpattern.pattern)
758 // In addition, we need all the other match pairs from the old candidate.
759 let other_match_pairs =
760 candidate.match_pairs.iter()
762 .filter(|&(index, _)| index != match_pair_index)
763 .map(|(_, mp)| mp.clone());
765 let all_match_pairs = consequent_match_pairs.chain(other_match_pairs).collect();
768 span: candidate.span,
769 match_pairs: all_match_pairs,
770 bindings: candidate.bindings.clone(),
771 ascriptions: candidate.ascriptions.clone(),
772 guard: candidate.guard.clone(),
773 arm_index: candidate.arm_index,
774 pat_index: candidate.pat_index,
775 pre_binding_block: candidate.pre_binding_block,
776 next_candidate_pre_binding_block: candidate.next_candidate_pre_binding_block,
780 fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
781 span_bug!(match_pair.pattern.span,
782 "simplifyable pattern found: {:?}",
786 fn const_range_contains(
788 range: PatternRange<'tcx>,
789 value: ty::Const<'tcx>,
791 use std::cmp::Ordering::*;
793 let param_env = ty::ParamEnv::empty().and(range.ty);
794 let tcx = self.hir.tcx();
796 let a = compare_const_vals(tcx, range.lo, value, param_env)?;
797 let b = compare_const_vals(tcx, value, range.hi, param_env)?;
799 match (b, range.end) {
801 (Equal, RangeEnd::Included) if a != Greater => Some(true),
806 fn values_not_contained_in_range(
808 range: PatternRange<'tcx>,
809 indices: &FxHashMap<ty::Const<'tcx>, usize>,
811 for &val in indices.keys() {
812 if self.const_range_contains(range, val)? {
821 fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
822 ty.is_integral() || ty.is_char() || ty.is_bool()