]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/matches/test.rs
Fix the IntTypeExt::to_ty() lifetime bounds
[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::BitVector;
23 use rustc::middle::const_val::{ConstVal, ConstInt};
24 use rustc::ty::{self, Ty};
25 use rustc::ty::util::IntTypeExt;
26 use rustc::mir::*;
27 use rustc::hir::RangeEnd;
28 use syntax_pos::Span;
29 use std::cmp::Ordering;
30
31 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
32     /// Identifies what test is needed to decide if `match_pair` is applicable.
33     ///
34     /// It is a bug to call this with a simplifyable pattern.
35     pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
36         match *match_pair.pattern.kind {
37             PatternKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => {
38                 Test {
39                     span: match_pair.pattern.span,
40                     kind: TestKind::Switch {
41                         adt_def: adt_def.clone(),
42                         variants: BitVector::new(self.hir.num_variants(adt_def)),
43                     },
44                 }
45             }
46
47             PatternKind::Constant { .. }
48             if is_switch_ty(match_pair.pattern.ty) => {
49                 // for integers, we use a SwitchInt match, which allows
50                 // us to handle more cases
51                 Test {
52                     span: match_pair.pattern.span,
53                     kind: TestKind::SwitchInt {
54                         switch_ty: match_pair.pattern.ty,
55
56                         // these maps are empty to start; cases are
57                         // added below in add_cases_to_switch
58                         options: vec![],
59                         indices: FxHashMap(),
60                     }
61                 }
62             }
63
64             PatternKind::Constant { ref value } => {
65                 Test {
66                     span: match_pair.pattern.span,
67                     kind: TestKind::Eq {
68                         value: value.clone(),
69                         ty: match_pair.pattern.ty.clone()
70                     }
71                 }
72             }
73
74             PatternKind::Range { ref lo, ref hi, ref end } => {
75                 Test {
76                     span: match_pair.pattern.span,
77                     kind: TestKind::Range {
78                         lo: Literal::Value { value: lo.clone() },
79                         hi: Literal::Value { value: hi.clone() },
80                         ty: match_pair.pattern.ty.clone(),
81                         end: end.clone(),
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::Array { .. } |
101             PatternKind::Slice { .. } |
102             PatternKind::Wild |
103             PatternKind::Binding { .. } |
104             PatternKind::Leaf { .. } |
105             PatternKind::Deref { .. } => {
106                 self.error_simplifyable(match_pair)
107             }
108         }
109     }
110
111     pub fn add_cases_to_switch<'pat>(&mut self,
112                                      test_lvalue: &Lvalue<'tcx>,
113                                      candidate: &Candidate<'pat, 'tcx>,
114                                      switch_ty: Ty<'tcx>,
115                                      options: &mut Vec<ConstVal>,
116                                      indices: &mut FxHashMap<ConstVal, usize>)
117                                      -> bool
118     {
119         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
120             Some(match_pair) => match_pair,
121             _ => { return false; }
122         };
123
124         match *match_pair.pattern.kind {
125             PatternKind::Constant { ref value } => {
126                 // if the lvalues match, the type should match
127                 assert_eq!(match_pair.pattern.ty, switch_ty);
128
129                 indices.entry(value.clone())
130                        .or_insert_with(|| {
131                            options.push(value.clone());
132                            options.len() - 1
133                        });
134                 true
135             }
136             PatternKind::Variant { .. } => {
137                 panic!("you should have called add_variants_to_switch instead!");
138             }
139             PatternKind::Range { .. } |
140             PatternKind::Slice { .. } |
141             PatternKind::Array { .. } |
142             PatternKind::Wild |
143             PatternKind::Binding { .. } |
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_lvalue: &Lvalue<'tcx>,
154                                         candidate: &Candidate<'pat, 'tcx>,
155                                         variants: &mut BitVector)
156                                         -> bool
157     {
158         let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
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                         lvalue: &Lvalue<'tcx>,
181                         test: &Test<'tcx>)
182                         -> Vec<BasicBlock> {
183         let source_info = self.source_info(test.span);
184         match test.kind {
185             TestKind::Switch { adt_def, ref variants } => {
186                 // Variants is a BitVec of indexes into adt_def.variants.
187                 let num_enum_variants = self.hir.num_variants(adt_def);
188                 let used_variants = variants.count();
189                 let mut otherwise_block = None;
190                 let mut target_blocks = Vec::with_capacity(num_enum_variants);
191                 let mut targets = Vec::with_capacity(used_variants + 1);
192                 let mut values = Vec::with_capacity(used_variants);
193                 let tcx = self.hir.tcx();
194                 for (idx, variant) in adt_def.variants.iter().enumerate() {
195                     target_blocks.place_back() <- if variants.contains(idx) {
196                         let discr = ConstInt::new_inttype(variant.disr_val, adt_def.discr_ty,
197                                                           tcx.sess.target.uint_type,
198                                                           tcx.sess.target.int_type).unwrap();
199                         values.push(discr);
200                         *(targets.place_back() <- self.cfg.start_new_block())
201                     } else {
202                         if otherwise_block.is_none() {
203                             otherwise_block = Some(self.cfg.start_new_block());
204                         }
205                         otherwise_block.unwrap()
206                     };
207                 }
208                 if let Some(otherwise_block) = otherwise_block {
209                     targets.push(otherwise_block);
210                 } else {
211                     values.pop();
212                 }
213                 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
214                        num_enum_variants, values, variants);
215                 let discr_ty = adt_def.discr_ty.to_ty(tcx);
216                 let discr = self.temp(discr_ty);
217                 self.cfg.push_assign(block, source_info, &discr,
218                                      Rvalue::Discriminant(lvalue.clone()));
219                 assert_eq!(values.len() + 1, targets.len());
220                 self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
221                     discr: Operand::Consume(discr),
222                     switch_ty: discr_ty,
223                     values: From::from(values),
224                     targets: targets
225                 });
226                 target_blocks
227             }
228
229             TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
230                 let (values, targets, ret) = if switch_ty.sty == ty::TyBool {
231                     assert!(options.len() > 0 && options.len() <= 2);
232                     let (true_bb, false_bb) = (self.cfg.start_new_block(),
233                                                self.cfg.start_new_block());
234                     let ret = match &options[0] {
235                         &ConstVal::Bool(true) => vec![true_bb, false_bb],
236                         &ConstVal::Bool(false) => vec![false_bb, true_bb],
237                         v => span_bug!(test.span, "expected boolean value but got {:?}", v)
238                     };
239                     (BOOL_SWITCH_TRUE.clone(), vec![true_bb, false_bb], ret)
240                 } else {
241                     // The switch may be inexhaustive so we
242                     // add a catch all block
243                     let otherwise = self.cfg.start_new_block();
244                     let targets: Vec<_> =
245                         options.iter()
246                                .map(|_| self.cfg.start_new_block())
247                                .chain(Some(otherwise))
248                                .collect();
249                     let values: Vec<_> = options.iter().map(|v|
250                         v.to_const_int().expect("switching on integral")
251                     ).collect();
252                     (From::from(values), targets.clone(), targets)
253                 };
254
255                 self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
256                     discr: Operand::Consume(lvalue.clone()),
257                     switch_ty: switch_ty,
258                     values: values,
259                     targets: targets.clone(),
260                 });
261                 ret
262             }
263
264             TestKind::Eq { ref value, mut ty } => {
265                 let mut val = Operand::Consume(lvalue.clone());
266
267                 // If we're using b"..." as a pattern, we need to insert an
268                 // unsizing coercion, as the byte string has the type &[u8; N].
269                 let expect = if let ConstVal::ByteStr(ref bytes) = *value {
270                     let tcx = self.hir.tcx();
271
272                     // Unsize the lvalue to &[u8], too, if necessary.
273                     if let ty::TyRef(region, mt) = ty.sty {
274                         if let ty::TyArray(_, _) = mt.ty.sty {
275                             ty = tcx.mk_imm_ref(region, tcx.mk_slice(tcx.types.u8));
276                             let val_slice = self.temp(ty);
277                             self.cfg.push_assign(block, source_info, &val_slice,
278                                                  Rvalue::Cast(CastKind::Unsize, val, ty));
279                             val = Operand::Consume(val_slice);
280                         }
281                     }
282
283                     assert!(ty.is_slice());
284
285                     let array_ty = tcx.mk_array(tcx.types.u8, bytes.len());
286                     let array_ref = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty);
287                     let array = self.literal_operand(test.span, array_ref, Literal::Value {
288                         value: value.clone()
289                     });
290
291                     let slice = self.temp(ty);
292                     self.cfg.push_assign(block, source_info, &slice,
293                                          Rvalue::Cast(CastKind::Unsize, array, ty));
294                     Operand::Consume(slice)
295                 } else {
296                     self.literal_operand(test.span, ty, Literal::Value {
297                         value: value.clone()
298                     })
299                 };
300
301                 // Use PartialEq::eq for &str and &[u8] slices, instead of BinOp::Eq.
302                 let fail = self.cfg.start_new_block();
303                 if let ty::TyRef(_, mt) = ty.sty {
304                     assert!(ty.is_slice());
305                     let eq_def_id = self.hir.tcx().lang_items.eq_trait().unwrap();
306                     let ty = mt.ty;
307                     let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
308
309                     let bool_ty = self.hir.bool_ty();
310                     let eq_result = self.temp(bool_ty);
311                     let eq_block = self.cfg.start_new_block();
312                     let cleanup = self.diverge_cleanup();
313                     self.cfg.terminate(block, source_info, TerminatorKind::Call {
314                         func: Operand::Constant(Constant {
315                             span: test.span,
316                             ty: mty,
317                             literal: method
318                         }),
319                         args: vec![val, expect],
320                         destination: Some((eq_result.clone(), eq_block)),
321                         cleanup: cleanup,
322                     });
323
324                     // check the result
325                     let block = self.cfg.start_new_block();
326                     self.cfg.terminate(eq_block, source_info, TerminatorKind::SwitchInt {
327                         discr: Operand::Consume(eq_result),
328                         switch_ty: self.hir.bool_ty(),
329                         values: BOOL_SWITCH_TRUE.clone(),
330                         targets: vec![block, fail],
331                     });
332                     vec![block, fail]
333                 } else {
334                     let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
335                     vec![block, fail]
336                 }
337             }
338
339             TestKind::Range { ref lo, ref hi, ty, ref end } => {
340                 // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
341                 let lo = self.literal_operand(test.span, ty.clone(), lo.clone());
342                 let hi = self.literal_operand(test.span, ty.clone(), hi.clone());
343                 let val = Operand::Consume(lvalue.clone());
344
345                 let fail = self.cfg.start_new_block();
346                 let block = self.compare(block, fail, test.span, BinOp::Le, lo, val.clone());
347                 let block = match *end {
348                     RangeEnd::Included => self.compare(block, fail, test.span, BinOp::Le, val, hi),
349                     RangeEnd::Excluded => self.compare(block, fail, test.span, BinOp::Lt, val, hi),
350                 };
351
352                 vec![block, fail]
353             }
354
355             TestKind::Len { len, op } => {
356                 let (usize_ty, bool_ty) = (self.hir.usize_ty(), self.hir.bool_ty());
357                 let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty));
358
359                 // actual = len(lvalue)
360                 self.cfg.push_assign(block, source_info,
361                                      &actual, Rvalue::Len(lvalue.clone()));
362
363                 // expected = <N>
364                 let expected = self.push_usize(block, source_info, len);
365
366                 // result = actual == expected OR result = actual < expected
367                 self.cfg.push_assign(block, source_info, &result,
368                                      Rvalue::BinaryOp(op,
369                                                       Operand::Consume(actual),
370                                                       Operand::Consume(expected)));
371
372                 // branch based on result
373                 let (false_bb, true_bb) = (self.cfg.start_new_block(),
374                                            self.cfg.start_new_block());
375                 self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
376                     discr: Operand::Consume(result),
377                     switch_ty: self.hir.bool_ty(),
378                     values: BOOL_SWITCH_TRUE.clone(),
379                     targets: vec![true_bb, false_bb],
380                 });
381                 vec![true_bb, false_bb]
382             }
383         }
384     }
385
386     fn compare(&mut self,
387                block: BasicBlock,
388                fail_block: BasicBlock,
389                span: Span,
390                op: BinOp,
391                left: Operand<'tcx>,
392                right: Operand<'tcx>) -> BasicBlock {
393         let bool_ty = self.hir.bool_ty();
394         let result = self.temp(bool_ty);
395
396         // result = op(left, right)
397         let source_info = self.source_info(span);
398         self.cfg.push_assign(block, source_info, &result,
399                              Rvalue::BinaryOp(op, left, right));
400
401         // branch based on result
402         let target_block = self.cfg.start_new_block();
403         self.cfg.terminate(block, source_info, TerminatorKind::SwitchInt {
404             discr: Operand::Consume(result),
405             switch_ty: self.hir.bool_ty(),
406             values: BOOL_SWITCH_TRUE.clone(),
407             targets: vec![target_block, fail_block]
408         });
409         target_block
410     }
411
412     /// Given that we are performing `test` against `test_lvalue`,
413     /// this job sorts out what the status of `candidate` will be
414     /// after the test. The `resulting_candidates` vector stores, for
415     /// each possible outcome of `test`, a vector of the candidates
416     /// that will result. This fn should add a (possibly modified)
417     /// clone of candidate into `resulting_candidates` wherever
418     /// appropriate.
419     ///
420     /// So, for example, if this candidate is `x @ Some(P0)` and the
421     /// test is a variant test, then we would add `(x as Option).0 @
422     /// P0` to the `resulting_candidates` entry corresponding to the
423     /// variant `Some`.
424     ///
425     /// However, in some cases, the test may just not be relevant to
426     /// candidate. For example, suppose we are testing whether `foo.x == 22`,
427     /// but in one match arm we have `Foo { x: _, ... }`... in that case,
428     /// the test for what value `x` has has no particular relevance
429     /// to this candidate. In such cases, this function just returns false
430     /// without doing anything. This is used by the overall `match_candidates`
431     /// algorithm to structure the match as a whole. See `match_candidates` for
432     /// more details.
433     ///
434     /// FIXME(#29623). In some cases, we have some tricky choices to
435     /// make.  for example, if we are testing that `x == 22`, but the
436     /// candidate is `x @ 13..55`, what should we do? In the event
437     /// that the test is true, we know that the candidate applies, but
438     /// in the event of false, we don't know that it *doesn't*
439     /// apply. For now, we return false, indicate that the test does
440     /// not apply to this candidate, but it might be we can get
441     /// tighter match code if we do something a bit different.
442     pub fn sort_candidate<'pat>(&mut self,
443                                 test_lvalue: &Lvalue<'tcx>,
444                                 test: &Test<'tcx>,
445                                 candidate: &Candidate<'pat, 'tcx>,
446                                 resulting_candidates: &mut [Vec<Candidate<'pat, 'tcx>>])
447                                 -> bool {
448         // Find the match_pair for this lvalue (if any). At present,
449         // afaik, there can be at most one. (In the future, if we
450         // adopted a more general `@` operator, there might be more
451         // than one, but it'd be very unusual to have two sides that
452         // both require tests; you'd expect one side to be simplified
453         // away.)
454         let tested_match_pair = candidate.match_pairs.iter()
455                                                      .enumerate()
456                                                      .filter(|&(_, mp)| mp.lvalue == *test_lvalue)
457                                                      .next();
458         let (match_pair_index, match_pair) = match tested_match_pair {
459             Some(pair) => pair,
460             None => {
461                 // We are not testing this lvalue. Therefore, this
462                 // candidate applies to ALL outcomes.
463                 return false;
464             }
465         };
466
467         match (&test.kind, &*match_pair.pattern.kind) {
468             // If we are performing a variant switch, then this
469             // informs variant patterns, but nothing else.
470             (&TestKind::Switch { adt_def: tested_adt_def, .. },
471              &PatternKind::Variant { adt_def, variant_index, ref subpatterns, .. }) => {
472                 assert_eq!(adt_def, tested_adt_def);
473                 let new_candidate =
474                     self.candidate_after_variant_switch(match_pair_index,
475                                                         adt_def,
476                                                         variant_index,
477                                                         subpatterns,
478                                                         candidate);
479                 resulting_candidates[variant_index].push(new_candidate);
480                 true
481             }
482             (&TestKind::Switch { .. }, _) => false,
483
484             // If we are performing a switch over integers, then this informs integer
485             // equality, but nothing else.
486             //
487             // FIXME(#29623) we could use PatternKind::Range to rule
488             // things out here, in some cases.
489             (&TestKind::SwitchInt { switch_ty: _, options: _, ref indices },
490              &PatternKind::Constant { ref value })
491             if is_switch_ty(match_pair.pattern.ty) => {
492                 let index = indices[value];
493                 let new_candidate = self.candidate_without_match_pair(match_pair_index,
494                                                                       candidate);
495                 resulting_candidates[index].push(new_candidate);
496                 true
497             }
498             (&TestKind::SwitchInt { .. }, _) => false,
499
500
501             (&TestKind::Len { len: test_len, op: BinOp::Eq },
502              &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
503                 let pat_len = (prefix.len() + suffix.len()) as u64;
504                 match (test_len.cmp(&pat_len), slice) {
505                     (Ordering::Equal, &None) => {
506                         // on true, min_len = len = $actual_length,
507                         // on false, len != $actual_length
508                         resulting_candidates[0].push(
509                             self.candidate_after_slice_test(match_pair_index,
510                                                             candidate,
511                                                             prefix,
512                                                             slice.as_ref(),
513                                                             suffix)
514                         );
515                         true
516                     }
517                     (Ordering::Less, _) => {
518                         // test_len < pat_len. If $actual_len = test_len,
519                         // then $actual_len < pat_len and we don't have
520                         // enough elements.
521                         resulting_candidates[1].push(candidate.clone());
522                         true
523                     }
524                     (Ordering::Equal, &Some(_)) | (Ordering::Greater, &Some(_)) => {
525                         // This can match both if $actual_len = test_len >= pat_len,
526                         // and if $actual_len > test_len. We can't advance.
527                         false
528                     }
529                     (Ordering::Greater, &None) => {
530                         // test_len != pat_len, so if $actual_len = test_len, then
531                         // $actual_len != pat_len.
532                         resulting_candidates[1].push(candidate.clone());
533                         true
534                     }
535                 }
536             }
537
538             (&TestKind::Len { len: test_len, op: BinOp::Ge },
539              &PatternKind::Slice { ref prefix, ref slice, ref suffix }) => {
540                 // the test is `$actual_len >= test_len`
541                 let pat_len = (prefix.len() + suffix.len()) as u64;
542                 match (test_len.cmp(&pat_len), slice) {
543                     (Ordering::Equal, &Some(_))  => {
544                         // $actual_len >= test_len = pat_len,
545                         // so we can match.
546                         resulting_candidates[0].push(
547                             self.candidate_after_slice_test(match_pair_index,
548                                                             candidate,
549                                                             prefix,
550                                                             slice.as_ref(),
551                                                             suffix)
552                         );
553                         true
554                     }
555                     (Ordering::Less, _) | (Ordering::Equal, &None) => {
556                         // test_len <= pat_len. If $actual_len < test_len,
557                         // then it is also < pat_len, so the test passing is
558                         // necessary (but insufficient).
559                         resulting_candidates[0].push(candidate.clone());
560                         true
561                     }
562                     (Ordering::Greater, &None) => {
563                         // test_len > pat_len. If $actual_len >= test_len > pat_len,
564                         // then we know we won't have a match.
565                         resulting_candidates[1].push(candidate.clone());
566                         true
567                     }
568                     (Ordering::Greater, &Some(_)) => {
569                         // test_len < pat_len, and is therefore less
570                         // strict. This can still go both ways.
571                         false
572                     }
573                 }
574             }
575
576             (&TestKind::Eq { .. }, _) |
577             (&TestKind::Range { .. }, _) |
578             (&TestKind::Len { .. }, _) => {
579                 // These are all binary tests.
580                 //
581                 // FIXME(#29623) we can be more clever here
582                 let pattern_test = self.test(&match_pair);
583                 if pattern_test.kind == test.kind {
584                     let new_candidate = self.candidate_without_match_pair(match_pair_index,
585                                                                           candidate);
586                     resulting_candidates[0].push(new_candidate);
587                     true
588                 } else {
589                     false
590                 }
591             }
592         }
593     }
594
595     fn candidate_without_match_pair<'pat>(&mut self,
596                                           match_pair_index: usize,
597                                           candidate: &Candidate<'pat, 'tcx>)
598                                           -> Candidate<'pat, 'tcx> {
599         let other_match_pairs =
600             candidate.match_pairs.iter()
601                                  .enumerate()
602                                  .filter(|&(index, _)| index != match_pair_index)
603                                  .map(|(_, mp)| mp.clone())
604                                  .collect();
605         Candidate {
606             span: candidate.span,
607             match_pairs: other_match_pairs,
608             bindings: candidate.bindings.clone(),
609             guard: candidate.guard.clone(),
610             arm_index: candidate.arm_index,
611         }
612     }
613
614     fn candidate_after_slice_test<'pat>(&mut self,
615                                         match_pair_index: usize,
616                                         candidate: &Candidate<'pat, 'tcx>,
617                                         prefix: &'pat [Pattern<'tcx>],
618                                         opt_slice: Option<&'pat Pattern<'tcx>>,
619                                         suffix: &'pat [Pattern<'tcx>])
620                                         -> Candidate<'pat, 'tcx> {
621         let mut new_candidate =
622             self.candidate_without_match_pair(match_pair_index, candidate);
623         self.prefix_slice_suffix(
624             &mut new_candidate.match_pairs,
625             &candidate.match_pairs[match_pair_index].lvalue,
626             prefix,
627             opt_slice,
628             suffix);
629
630         new_candidate
631     }
632
633     fn candidate_after_variant_switch<'pat>(&mut self,
634                                             match_pair_index: usize,
635                                             adt_def: &'tcx ty::AdtDef,
636                                             variant_index: usize,
637                                             subpatterns: &'pat [FieldPattern<'tcx>],
638                                             candidate: &Candidate<'pat, 'tcx>)
639                                             -> Candidate<'pat, 'tcx> {
640         let match_pair = &candidate.match_pairs[match_pair_index];
641
642         // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
643         // we want to create a set of derived match-patterns like
644         // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
645         let elem = ProjectionElem::Downcast(adt_def, variant_index);
646         let downcast_lvalue = match_pair.lvalue.clone().elem(elem); // `(x as Variant)`
647         let consequent_match_pairs =
648             subpatterns.iter()
649                        .map(|subpattern| {
650                            // e.g., `(x as Variant).0`
651                            let lvalue = downcast_lvalue.clone().field(subpattern.field,
652                                                                       subpattern.pattern.ty);
653                            // e.g., `(x as Variant).0 @ P1`
654                            MatchPair::new(lvalue, &subpattern.pattern)
655                        });
656
657         // In addition, we need all the other match pairs from the old candidate.
658         let other_match_pairs =
659             candidate.match_pairs.iter()
660                                  .enumerate()
661                                  .filter(|&(index, _)| index != match_pair_index)
662                                  .map(|(_, mp)| mp.clone());
663
664         let all_match_pairs = consequent_match_pairs.chain(other_match_pairs).collect();
665
666         Candidate {
667             span: candidate.span,
668             match_pairs: all_match_pairs,
669             bindings: candidate.bindings.clone(),
670             guard: candidate.guard.clone(),
671             arm_index: candidate.arm_index,
672         }
673     }
674
675     fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
676         span_bug!(match_pair.pattern.span,
677                   "simplifyable pattern found: {:?}",
678                   match_pair.pattern)
679     }
680 }
681
682 fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
683     ty.is_integral() || ty.is_char() || ty.is_bool()
684 }