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