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