]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/matches/test.rs
Create fewer basic blocks in match MIR lowering
[rust.git] / src / librustc_mir / build / matches / test.rs
1 // Testing candidates
2 //
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.
7
8 use crate::build::Builder;
9 use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
10 use crate::hair::*;
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, adjustment::{PointerCast}};
15 use rustc::ty::util::IntTypeExt;
16 use rustc::ty::layout::VariantIdx;
17 use rustc::mir::*;
18 use rustc::hir::{RangeEnd, Mutability};
19 use std::cmp::Ordering;
20
21 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
22     /// Identifies what test is needed to decide if `match_pair` is applicable.
23     ///
24     /// It is a bug to call this with a simplifiable pattern.
25     pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
26         match *match_pair.pattern.kind {
27             PatternKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => {
28                 Test {
29                     span: match_pair.pattern.span,
30                     kind: TestKind::Switch {
31                         adt_def: adt_def.clone(),
32                         variants: BitSet::new_empty(adt_def.variants.len()),
33                     },
34                 }
35             }
36
37             PatternKind::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
38                 // For integers, we use a `SwitchInt` match, which allows
39                 // us to handle more cases.
40                 Test {
41                     span: match_pair.pattern.span,
42                     kind: TestKind::SwitchInt {
43                         switch_ty: match_pair.pattern.ty,
44
45                         // these maps are empty to start; cases are
46                         // added below in add_cases_to_switch
47                         options: vec![],
48                         indices: Default::default(),
49                     }
50                 }
51             }
52
53             PatternKind::Constant { value } => {
54                 Test {
55                     span: match_pair.pattern.span,
56                     kind: TestKind::Eq {
57                         value,
58                         ty: match_pair.pattern.ty.clone()
59                     }
60                 }
61             }
62
63             PatternKind::Range(range) => {
64                 assert!(range.ty == match_pair.pattern.ty);
65                 Test {
66                     span: match_pair.pattern.span,
67                     kind: TestKind::Range(range),
68                 }
69             }
70
71             PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
72                 let len = prefix.len() + suffix.len();
73                 let op = if slice.is_some() {
74                     BinOp::Ge
75                 } else {
76                     BinOp::Eq
77                 };
78                 Test {
79                     span: match_pair.pattern.span,
80                     kind: TestKind::Len { len: len as u64, op: op },
81                 }
82             }
83
84             PatternKind::AscribeUserType { .. } |
85             PatternKind::Array { .. } |
86             PatternKind::Wild |
87             PatternKind::Binding { .. } |
88             PatternKind::Leaf { .. } |
89             PatternKind::Deref { .. } => {
90                 self.error_simplifyable(match_pair)
91             }
92         }
93     }
94
95     pub fn add_cases_to_switch<'pat>(&mut self,
96                                      test_place: &Place<'tcx>,
97                                      candidate: &Candidate<'pat, 'tcx>,
98                                      switch_ty: Ty<'tcx>,
99                                      options: &mut Vec<u128>,
100                                      indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
101                                      -> bool
102     {
103         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
104             Some(match_pair) => match_pair,
105             _ => { return false; }
106         };
107
108         match *match_pair.pattern.kind {
109             PatternKind::Constant { value } => {
110                 let switch_ty = ty::ParamEnv::empty().and(switch_ty);
111                 indices.entry(value)
112                        .or_insert_with(|| {
113                            options.push(value.unwrap_bits(self.hir.tcx(), switch_ty));
114                            options.len() - 1
115                        });
116                 true
117             }
118             PatternKind::Variant { .. } => {
119                 panic!("you should have called add_variants_to_switch instead!");
120             }
121             PatternKind::Range(range) => {
122                 // Check that none of the switch values are in the range.
123                 self.values_not_contained_in_range(range, indices)
124                     .unwrap_or(false)
125             }
126             PatternKind::Slice { .. } |
127             PatternKind::Array { .. } |
128             PatternKind::Wild |
129             PatternKind::Binding { .. } |
130             PatternKind::AscribeUserType { .. } |
131             PatternKind::Leaf { .. } |
132             PatternKind::Deref { .. } => {
133                 // don't know how to add these patterns to a switch
134                 false
135             }
136         }
137     }
138
139     pub fn add_variants_to_switch<'pat>(&mut self,
140                                         test_place: &Place<'tcx>,
141                                         candidate: &Candidate<'pat, 'tcx>,
142                                         variants: &mut BitSet<VariantIdx>)
143                                         -> bool
144     {
145         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
146             Some(match_pair) => match_pair,
147             _ => { return false; }
148         };
149
150         match *match_pair.pattern.kind {
151             PatternKind::Variant { adt_def: _ , variant_index,  .. } => {
152                 // We have a pattern testing for variant `variant_index`
153                 // set the corresponding index to true
154                 variants.insert(variant_index);
155                 true
156             }
157             _ => {
158                 // don't know how to add these patterns to a switch
159                 false
160             }
161         }
162     }
163
164     pub fn perform_test(
165         &mut self,
166         block: BasicBlock,
167         place: &Place<'tcx>,
168         test: &Test<'tcx>,
169         target_blocks: Vec<BasicBlock>,
170     ) {
171         debug!("perform_test({:?}, {:?}: {:?}, {:?})",
172                block,
173                place,
174                place.ty(&self.local_decls, self.hir.tcx()),
175                test);
176
177         let source_info = self.source_info(test.span);
178         match test.kind {
179             TestKind::Switch { adt_def, ref variants } => {
180                 // Variants is a BitVec of indexes into adt_def.variants.
181                 let num_enum_variants = adt_def.variants.len();
182                 let used_variants = variants.count();
183                 debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
184                 let otherwise_block = *target_blocks.last().unwrap();
185                 let mut targets = Vec::with_capacity(used_variants + 1);
186                 let mut values = Vec::with_capacity(used_variants);
187                 let tcx = self.hir.tcx();
188                 for (idx, discr) in adt_def.discriminants(tcx) {
189                     if variants.contains(idx) {
190                         debug_assert_ne!(
191                             target_blocks[idx.index()],
192                             otherwise_block,
193                             "no canididates for tested discriminant: {:?}",
194                             discr,
195                         );
196                         values.push(discr.val);
197                         targets.push(target_blocks[idx.index()]);
198                     } else {
199                         debug_assert_eq!(
200                             target_blocks[idx.index()],
201                             otherwise_block,
202                             "found canididates for untested discriminant: {:?}",
203                             discr,
204                         );
205                     }
206                 }
207                 targets.push(otherwise_block);
208                 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
209                        num_enum_variants, values, variants);
210                 let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
211                 let discr = self.temp(discr_ty, test.span);
212                 self.cfg.push_assign(block, source_info, &discr,
213                                      Rvalue::Discriminant(place.clone()));
214                 assert_eq!(values.len() + 1, targets.len());
215                 self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
216                     discr: Operand::Move(discr),
217                     switch_ty: discr_ty,
218                     values: From::from(values),
219                     targets,
220                 });
221             }
222
223             TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
224                 let terminator = if switch_ty.sty == ty::Bool {
225                     assert!(options.len() > 0 && options.len() <= 2);
226                     if let [first_bb, second_bb] = *target_blocks {
227                         let (true_bb, false_bb) = match options[0] {
228                             1 => (first_bb, second_bb),
229                             0 => (second_bb, first_bb),
230                             v => span_bug!(test.span, "expected boolean value but got {:?}", v)
231                         };
232                         TerminatorKind::if_(
233                             self.hir.tcx(),
234                             Operand::Copy(place.clone()),
235                             true_bb,
236                             false_bb,
237                         )
238                     } else {
239                         bug!("`TestKind::SwitchInt` on `bool` should have two targets")
240                     }
241                 } else {
242                     // The switch may be inexhaustive so we have a catch all block
243                     debug_assert_eq!(options.len() + 1, target_blocks.len());
244                     TerminatorKind::SwitchInt {
245                         discr: Operand::Copy(place.clone()),
246                         switch_ty,
247                         values: options.clone().into(),
248                         targets: target_blocks,
249                     }
250                 };
251                 self.cfg.terminate(block, source_info, terminator);
252             }
253
254             TestKind::Eq { value, ty } => {
255                 // Use `PartialEq::eq` instead of `BinOp::Eq`
256                 // (the binop can only handle primitives)
257                 if let [success, fail] = *target_blocks {
258                     if !ty.is_scalar() {
259                         self.non_scalar_compare(
260                             block,
261                             success,
262                             fail,
263                             source_info,
264                             value,
265                             place,
266                             ty,
267                         );
268                     } else {
269                         let val = Operand::Copy(place.clone());
270                         let expect = self.literal_operand(test.span, ty, value);
271                         self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
272                     }
273                 } else {
274                     bug!("`TestKind::Eq` should have two target blocks")
275                 };
276             }
277
278             TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => {
279                 // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
280                 let lo = self.literal_operand(test.span, ty, lo);
281                 let hi = self.literal_operand(test.span, ty, hi);
282                 let val = Operand::Copy(place.clone());
283
284                 if let [success, fail] = *target_blocks {
285                     let lower_bound_success = self.cfg.start_new_block();
286
287                     self.compare(
288                         block,
289                         lower_bound_success,
290                         fail,
291                         source_info,
292                         BinOp::Le,
293                         lo,
294                         val.clone(),
295                     );
296                     let op = match *end {
297                         RangeEnd::Included => BinOp::Le,
298                         RangeEnd::Excluded => BinOp::Lt,
299                     };
300                     self.compare(lower_bound_success, success, fail, source_info, op, val, hi);
301                 } else {
302                     bug!("`TestKind::Range` should have two target blocks");
303                 }
304             }
305
306             TestKind::Len { len, op } => {
307                 let usize_ty = self.hir.usize_ty();
308                 let actual = self.temp(usize_ty, test.span);
309
310                 // actual = len(place)
311                 self.cfg.push_assign(block, source_info,
312                                      &actual, Rvalue::Len(place.clone()));
313
314                 // expected = <N>
315                 let expected = self.push_usize(block, source_info, len);
316
317                 if let [true_bb, false_bb] = *target_blocks {
318                     // result = actual == expected OR result = actual < expected
319                     // branch based on result
320                     self.compare(
321                         block,
322                         true_bb,
323                         false_bb,
324                         source_info,
325                         op,
326                         Operand::Move(actual),
327                         Operand::Move(expected),
328                     );
329                 } else {
330                     bug!("`TestKind::Len` should have two target blocks");
331                 }
332             }
333         }
334     }
335
336     /// Compare using the provided built-in comparison operator
337     fn compare(
338         &mut self,
339         block: BasicBlock,
340         success_block: BasicBlock,
341         fail_block: BasicBlock,
342         source_info: SourceInfo,
343         op: BinOp,
344         left: Operand<'tcx>,
345         right: Operand<'tcx>,
346     ) {
347         let bool_ty = self.hir.bool_ty();
348         let result = self.temp(bool_ty, source_info.span);
349
350         // result = op(left, right)
351         self.cfg.push_assign(
352             block,
353             source_info,
354             &result,
355             Rvalue::BinaryOp(op, left, right),
356         );
357
358         // branch based on result
359         self.cfg.terminate(
360             block,
361             source_info,
362             TerminatorKind::if_(
363                 self.hir.tcx(),
364                 Operand::Move(result),
365                 success_block,
366                 fail_block,
367             ),
368         );
369     }
370
371     /// Compare using `std::compare::PartialEq::eq`
372     fn non_scalar_compare(
373         &mut self,
374         block: BasicBlock,
375         success_block: BasicBlock,
376         fail_block: BasicBlock,
377         source_info: SourceInfo,
378         value: &'tcx ty::Const<'tcx>,
379         place: &Place<'tcx>,
380         mut ty: Ty<'tcx>,
381     ) {
382         use rustc::middle::lang_items::EqTraitLangItem;
383
384         let mut expect = self.literal_operand(source_info.span, ty, value);
385         let val = Operand::Copy(place.clone());
386
387         // If we're using `b"..."` as a pattern, we need to insert an
388         // unsizing coercion, as the byte string has the type `&[u8; N]`.
389         //
390         // We want to do this even when the scrutinee is a reference to an
391         // array, so we can call `<[u8]>::eq` rather than having to find an
392         // `<[u8; N]>::eq`.
393         let unsize = |ty: Ty<'tcx>| match ty.sty {
394             ty::Ref(region, rty, _) => match rty.sty {
395                 ty::Array(inner_ty, n) => Some((region, inner_ty, n)),
396                 _ => None,
397             },
398             _ => None,
399         };
400         let opt_ref_ty = unsize(ty);
401         let opt_ref_test_ty = unsize(value.ty);
402         let mut place = place.clone();
403         match (opt_ref_ty, opt_ref_test_ty) {
404             // nothing to do, neither is an array
405             (None, None) => {},
406             (Some((region, elem_ty, _)), _) |
407             (None, Some((region, elem_ty, _))) => {
408                 let tcx = self.hir.tcx();
409                 // make both a slice
410                 ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
411                 if opt_ref_ty.is_some() {
412                     place = self.temp(ty, source_info.span);
413                     self.cfg.push_assign(
414                         block, source_info, &place, Rvalue::Cast(
415                             CastKind::Pointer(PointerCast::Unsize), val, ty
416                         )
417                     );
418                 }
419                 if opt_ref_test_ty.is_some() {
420                     let array = self.literal_operand(
421                         source_info.span,
422                         value.ty,
423                         value,
424                     );
425
426                     let slice = self.temp(ty, source_info.span);
427                     self.cfg.push_assign(
428                         block, source_info, &slice, Rvalue::Cast(
429                             CastKind::Pointer(PointerCast::Unsize), array, ty
430                         )
431                     );
432                     expect = Operand::Move(slice);
433                 }
434             },
435         }
436         let eq_def_id = self.hir.tcx().require_lang_item(EqTraitLangItem);
437         let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]);
438
439         let re_erased = self.hir.tcx().lifetimes.re_erased;
440         // take the argument by reference
441         let tam = ty::TypeAndMut {
442             ty,
443             mutbl: Mutability::MutImmutable,
444         };
445         let ref_ty = self.hir.tcx().mk_ref(re_erased, tam);
446
447         // let lhs_ref_place = &lhs;
448         let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, place);
449         let lhs_ref_place = self.temp(ref_ty, source_info.span);
450         self.cfg.push_assign(block, source_info, &lhs_ref_place, ref_rvalue);
451         let val = Operand::Move(lhs_ref_place);
452
453         // let rhs_place = rhs;
454         let rhs_place = self.temp(ty, source_info.span);
455         self.cfg.push_assign(block, source_info, &rhs_place, Rvalue::Use(expect));
456
457         // let rhs_ref_place = &rhs_place;
458         let ref_rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, rhs_place);
459         let rhs_ref_place = self.temp(ref_ty, source_info.span);
460         self.cfg.push_assign(block, source_info, &rhs_ref_place, ref_rvalue);
461         let expect = Operand::Move(rhs_ref_place);
462
463         let bool_ty = self.hir.bool_ty();
464         let eq_result = self.temp(bool_ty, source_info.span);
465         let eq_block = self.cfg.start_new_block();
466         let cleanup = self.diverge_cleanup();
467         self.cfg.terminate(block, source_info, TerminatorKind::Call {
468             func: Operand::Constant(box Constant {
469                 span: source_info.span,
470                 ty: mty,
471
472                 // FIXME(#54571): This constant comes from user
473                 // input (a constant in a pattern).  Are
474                 // there forms where users can add type
475                 // annotations here?  For example, an
476                 // associated constant? Need to
477                 // experiment.
478                 user_ty: None,
479
480                 literal: method,
481             }),
482             args: vec![val, expect],
483             destination: Some((eq_result.clone(), eq_block)),
484             cleanup: Some(cleanup),
485             from_hir_call: false,
486         });
487
488         // check the result
489         self.cfg.terminate(
490             eq_block,
491             source_info,
492             TerminatorKind::if_(
493                 self.hir.tcx(),
494                 Operand::Move(eq_result),
495                 success_block,
496                 fail_block,
497             ),
498         );
499     }
500
501     /// Given that we are performing `test` against `test_place`, this job
502     /// sorts out what the status of `candidate` will be after the test. See
503     /// `test_candidates` for the usage of this function. The returned index is
504     /// the index that this candiate should be placed in the
505     /// `target_candidates` vec. The candidate may be modified to update its
506     /// `match_pairs`.
507     ///
508     /// So, for example, if this candidate is `x @ Some(P0)` and the `Test` is
509     /// a variant test, then we would modify the candidate to be `(x as
510     /// Option).0 @ P0` and return the index corresponding to the variant
511     /// `Some`.
512     ///
513     /// However, in some cases, the test may just not be relevant to candidate.
514     /// For example, suppose we are testing whether `foo.x == 22`, but in one
515     /// match arm we have `Foo { x: _, ... }`... in that case, the test for
516     /// what value `x` has has no particular relevance to this candidate. In
517     /// such cases, this function just returns None without doing anything.
518     /// This is used by the overall `match_candidates` algorithm to structure
519     /// the match as a whole. See `match_candidates` for more details.
520     ///
521     /// FIXME(#29623). In some cases, we have some tricky choices to make.  for
522     /// example, if we are testing that `x == 22`, but the candidate is `x @
523     /// 13..55`, what should we do? In the event that the test is true, we know
524     /// that the candidate applies, but in the event of false, we don't know
525     /// that it *doesn't* apply. For now, we return false, indicate that the
526     /// test does not apply to this candidate, but it might be we can get
527     /// tighter match code if we do something a bit different.
528     pub fn sort_candidate<'pat>(
529         &mut self,
530         test_place: &Place<'tcx>,
531         test: &Test<'tcx>,
532         candidate: &mut Candidate<'pat, 'tcx>,
533     ) -> Option<usize> {
534         // Find the match_pair for this place (if any). At present,
535         // afaik, there can be at most one. (In the future, if we
536         // adopted a more general `@` operator, there might be more
537         // than one, but it'd be very unusual to have two sides that
538         // both require tests; you'd expect one side to be simplified
539         // away.)
540         let (match_pair_index, match_pair) = candidate.match_pairs
541             .iter()
542             .enumerate()
543             .find(|&(_, mp)| mp.place == *test_place)?;
544
545         match (&test.kind, &*match_pair.pattern.kind) {
546             // If we are performing a variant switch, then this
547             // informs variant patterns, but nothing else.
548             (&TestKind::Switch { adt_def: tested_adt_def, .. },
549              &PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. }) => {
550                 assert_eq!(adt_def, tested_adt_def);
551                 self.candidate_after_variant_switch(match_pair_index,
552                                                     adt_def,
553                                                     variant_index,
554                                                     subpatterns,
555                                                     candidate);
556                 Some(variant_index.as_usize())
557             }
558
559             (&TestKind::Switch { .. }, _) => None,
560
561             // If we are performing a switch over integers, then this informs integer
562             // equality, but nothing else.
563             //
564             // FIXME(#29623) we could use PatternKind::Range to rule
565             // things out here, in some cases.
566             (&TestKind::SwitchInt { switch_ty: _, options: _, ref indices },
567              &PatternKind::Constant { ref value })
568             if is_switch_ty(match_pair.pattern.ty) => {
569                 let index = indices[value];
570                 self.candidate_without_match_pair(match_pair_index, candidate);
571                 Some(index)
572             }
573
574             (&TestKind::SwitchInt { switch_ty: _, ref options, ref indices },
575              &PatternKind::Range(range)) => {
576                 let not_contained = self
577                     .values_not_contained_in_range(range, indices)
578                     .unwrap_or(false);
579
580                 if not_contained {
581                     // No switch values are contained in the pattern range,
582                     // so the pattern can be matched only if this test fails.
583                     let otherwise = options.len();
584                     Some(otherwise)
585                 } else {
586                     None
587                 }
588             }
589
590             (&TestKind::SwitchInt { .. }, _) => None,
591
592             (&TestKind::Len { len: test_len, op: BinOp::Eq },
593              &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
594                 let pat_len = (prefix.len() + suffix.len()) as u64;
595                 match (test_len.cmp(&pat_len), slice) {
596                     (Ordering::Equal, &None) => {
597                         // on true, min_len = len = $actual_length,
598                         // on false, len != $actual_length
599                         self.candidate_after_slice_test(match_pair_index,
600                                                         candidate,
601                                                         prefix,
602                                                         slice.as_ref(),
603                                                         suffix);
604                         Some(0)
605                     }
606                     (Ordering::Less, _) => {
607                         // test_len < pat_len. If $actual_len = test_len,
608                         // then $actual_len < pat_len and we don't have
609                         // enough elements.
610                         Some(1)
611                     }
612                     (Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => {
613                         // This can match both if $actual_len = test_len >= pat_len,
614                         // and if $actual_len > test_len. We can't advance.
615                         None
616                     }
617                     (Ordering::Greater, &None) => {
618                         // test_len != pat_len, so if $actual_len = test_len, then
619                         // $actual_len != pat_len.
620                         Some(1)
621                     }
622                 }
623             }
624
625             (&TestKind::Len { len: test_len, op: BinOp::Ge },
626              &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
627                 // the test is `$actual_len >= test_len`
628                 let pat_len = (prefix.len() + suffix.len()) as u64;
629                 match (test_len.cmp(&pat_len), slice) {
630                     (Ordering::Equal, &Some(_))  => {
631                         // $actual_len >= test_len = pat_len,
632                         // so we can match.
633                         self.candidate_after_slice_test(match_pair_index,
634                                                         candidate,
635                                                         prefix,
636                                                         slice.as_ref(),
637                                                         suffix);
638                         Some(0)
639                     }
640                     (Ordering::Less, _) | (Ordering::Equal, &None) => {
641                         // test_len <= pat_len. If $actual_len < test_len,
642                         // then it is also < pat_len, so the test passing is
643                         // necessary (but insufficient).
644                         Some(0)
645                     }
646                     (Ordering::Greater, &None) => {
647                         // test_len > pat_len. If $actual_len >= test_len > pat_len,
648                         // then we know we won't have a match.
649                         Some(1)
650                     }
651                     (Ordering::Greater, &Some(_)) => {
652                         // test_len < pat_len, and is therefore less
653                         // strict. This can still go both ways.
654                         None
655                     }
656                 }
657             }
658
659             (&TestKind::Range(test),
660              &PatternKind::Range(pat)) => {
661                 if test == pat {
662                     self.candidate_without_match_pair(
663                         match_pair_index,
664                         candidate,
665                     );
666                     return Some(0);
667                 }
668
669                 let no_overlap = (|| {
670                     use std::cmp::Ordering::*;
671                     use rustc::hir::RangeEnd::*;
672
673                     let param_env = ty::ParamEnv::empty().and(test.ty);
674                     let tcx = self.hir.tcx();
675
676                     let lo = compare_const_vals(tcx, test.lo, pat.hi, param_env)?;
677                     let hi = compare_const_vals(tcx, test.hi, pat.lo, param_env)?;
678
679                     match (test.end, pat.end, lo, hi) {
680                         // pat < test
681                         (_, _, Greater, _) |
682                         (_, Excluded, Equal, _) |
683                         // pat > test
684                         (_, _, _, Less) |
685                         (Excluded, _, _, Equal) => Some(true),
686                         _ => Some(false),
687                     }
688                 })();
689
690                 if no_overlap == Some(true) {
691                     // Testing range does not overlap with pattern range,
692                     // so the pattern can be matched only if this test fails.
693                     Some(1)
694                 } else {
695                     None
696                 }
697             }
698
699             (&TestKind::Range(range), &PatternKind::Constant { value }) => {
700                 if self.const_range_contains(range, value) == Some(false) {
701                     // `value` is not contained in the testing range,
702                     // so `value` can be matched only if this test fails.
703                     Some(1)
704                 } else {
705                     None
706                 }
707             }
708
709             (&TestKind::Range { .. }, _) => None,
710
711             (&TestKind::Eq { .. }, _) |
712             (&TestKind::Len { .. }, _) => {
713                 // These are all binary tests.
714                 //
715                 // FIXME(#29623) we can be more clever here
716                 let pattern_test = self.test(&match_pair);
717                 if pattern_test.kind == test.kind {
718                     self.candidate_without_match_pair(match_pair_index, candidate);
719                     Some(0)
720                 } else {
721                     None
722                 }
723             }
724         }
725     }
726
727     fn candidate_without_match_pair(
728         &mut self,
729         match_pair_index: usize,
730         candidate: &mut Candidate<'_, 'tcx>,
731     ) {
732         candidate.match_pairs.remove(match_pair_index);
733     }
734
735     fn candidate_after_slice_test<'pat>(&mut self,
736                                         match_pair_index: usize,
737                                         candidate: &mut Candidate<'pat, 'tcx>,
738                                         prefix: &'pat [Pattern<'tcx>],
739                                         opt_slice: Option<&'pat Pattern<'tcx>>,
740                                         suffix: &'pat [Pattern<'tcx>]) {
741         let removed_place = candidate.match_pairs.remove(match_pair_index).place;
742         self.prefix_slice_suffix(
743             &mut candidate.match_pairs,
744             &removed_place,
745             prefix,
746             opt_slice,
747             suffix);
748     }
749
750     fn candidate_after_variant_switch<'pat>(
751         &mut self,
752         match_pair_index: usize,
753         adt_def: &'tcx ty::AdtDef,
754         variant_index: VariantIdx,
755         subpatterns: &'pat [FieldPattern<'tcx>],
756         candidate: &mut Candidate<'pat, 'tcx>,
757     ) {
758         let match_pair = candidate.match_pairs.remove(match_pair_index);
759
760         // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
761         // we want to create a set of derived match-patterns like
762         // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
763         let elem = ProjectionElem::Downcast(
764             Some(adt_def.variants[variant_index].ident.name), variant_index);
765         let downcast_place = match_pair.place.elem(elem); // `(x as Variant)`
766         let consequent_match_pairs =
767             subpatterns.iter()
768                        .map(|subpattern| {
769                            // e.g., `(x as Variant).0`
770                            let place = downcast_place.clone().field(subpattern.field,
771                                                                       subpattern.pattern.ty);
772                            // e.g., `(x as Variant).0 @ P1`
773                            MatchPair::new(place, &subpattern.pattern)
774                        });
775
776         candidate.match_pairs.extend(consequent_match_pairs);
777     }
778
779     fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
780         span_bug!(match_pair.pattern.span,
781                   "simplifyable pattern found: {:?}",
782                   match_pair.pattern)
783     }
784
785     fn const_range_contains(
786         &self,
787         range: PatternRange<'tcx>,
788         value: &'tcx ty::Const<'tcx>,
789     ) -> Option<bool> {
790         use std::cmp::Ordering::*;
791
792         let param_env = ty::ParamEnv::empty().and(range.ty);
793         let tcx = self.hir.tcx();
794
795         let a = compare_const_vals(tcx, range.lo, value, param_env)?;
796         let b = compare_const_vals(tcx, value, range.hi, param_env)?;
797
798         match (b, range.end) {
799             (Less, _) |
800             (Equal, RangeEnd::Included) if a != Greater => Some(true),
801             _ => Some(false),
802         }
803     }
804
805     fn values_not_contained_in_range(
806         &self,
807         range: PatternRange<'tcx>,
808         indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>,
809     ) -> Option<bool> {
810         for &val in indices.keys() {
811             if self.const_range_contains(range, val)? {
812                 return Some(false);
813             }
814         }
815
816         Some(true)
817     }
818 }
819
820 impl Test<'_> {
821     pub(super) fn targets(&self) -> usize {
822         match self.kind {
823             TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => {
824                 2
825             }
826             TestKind::Switch { adt_def, .. } => {
827                 adt_def.variants.len() + 1
828             }
829             TestKind::SwitchInt { switch_ty, ref options, .. } => {
830                 if switch_ty.is_bool() {
831                     2
832                 } else {
833                     options.len() + 1
834                 }
835             }
836         }
837     }
838 }
839
840 fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
841     ty.is_integral() || ty.is_char() || ty.is_bool()
842 }