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