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.
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.
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.
19 use build::matches::{Candidate, MatchPair, Test, TestKind};
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;
26 use rustc::hir::{RangeEnd, Mutability};
28 use std::cmp::Ordering;
30 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
31 /// Identifies what test is needed to decide if `match_pair` is applicable.
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: _ } => {
38 span: match_pair.pattern.span,
39 kind: TestKind::Switch {
40 adt_def: adt_def.clone(),
41 variants: BitArray::new(adt_def.variants.len()),
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
51 span: match_pair.pattern.span,
52 kind: TestKind::SwitchInt {
53 switch_ty: match_pair.pattern.ty,
55 // these maps are empty to start; cases are
56 // added below in add_cases_to_switch
63 PatternKind::Constant { value } => {
65 span: match_pair.pattern.span,
68 ty: match_pair.pattern.ty.clone()
73 PatternKind::Range { lo, hi, ty, end } => {
74 assert!(ty == match_pair.pattern.ty);
76 span: match_pair.pattern.span,
77 kind: TestKind::Range {
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() {
95 span: match_pair.pattern.span,
96 kind: TestKind::Len { len: len as u64, op: op },
100 PatternKind::AscribeUserType { .. } |
101 PatternKind::Array { .. } |
102 PatternKind::Slice { .. } |
104 PatternKind::Binding { .. } |
105 PatternKind::Leaf { .. } |
106 PatternKind::Deref { .. } => {
107 self.error_simplifyable(match_pair)
112 pub fn add_cases_to_switch<'pat>(&mut self,
113 test_place: &Place<'tcx>,
114 candidate: &Candidate<'pat, 'tcx>,
116 options: &mut Vec<u128>,
117 indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
120 let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
121 Some(match_pair) => match_pair,
122 _ => { return false; }
125 match *match_pair.pattern.kind {
126 PatternKind::Constant { value } => {
127 let switch_ty = ty::ParamEnv::empty().and(switch_ty);
130 options.push(value.unwrap_bits(self.hir.tcx(), switch_ty));
135 PatternKind::Variant { .. } => {
136 panic!("you should have called add_variants_to_switch instead!");
138 PatternKind::Range { .. } |
139 PatternKind::Slice { .. } |
140 PatternKind::Array { .. } |
142 PatternKind::Binding { .. } |
143 PatternKind::AscribeUserType { .. } |
144 PatternKind::Leaf { .. } |
145 PatternKind::Deref { .. } => {
146 // don't know how to add these patterns to a switch
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>)
158 let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
159 Some(match_pair) => match_pair,
160 _ => { return false; }
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);
171 // don't know how to add these patterns to a switch
177 /// Generates the code to perform a test.
178 pub fn perform_test(&mut self,
183 debug!("perform_test({:?}, {:?}: {:?}, {:?})",
186 place.ty(&self.local_decls, self.hir.tcx()),
188 let source_info = self.source_info(test.span);
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()
205 if otherwise_block.is_none() {
206 otherwise_block = Some(self.cfg.start_new_block());
208 otherwise_block.unwrap()
211 if let Some(otherwise_block) = otherwise_block {
212 targets.push(otherwise_block);
214 targets.push(self.unreachable_block());
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),
226 values: From::from(values),
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)
242 (ret, TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place.clone()),
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<_> =
250 .map(|_| self.cfg.start_new_block())
251 .chain(Some(otherwise))
253 (targets.clone(), TerminatorKind::SwitchInt {
254 discr: Operand::Copy(place.clone()),
256 values: options.clone().into(),
260 self.cfg.terminate(block, source_info, terminator);
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();
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].
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
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)),
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
290 (Some((region, elem_ty, _)), _) |
291 (None, Some((region, elem_ty, _))) => {
292 let tcx = self.hir.tcx();
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));
300 if opt_ref_test_ty.is_some() {
301 let array = self.literal_operand(
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);
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()]);
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 {
322 mutbl: Mutability::MutImmutable,
324 let ref_ty = self.hir.tcx().mk_ref(region, tam);
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);
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));
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);
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 {
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
361 args: vec![val, expect],
362 destination: Some((eq_result.clone(), eq_block)),
363 cleanup: Some(cleanup),
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),
374 let block = self.compare(block, fail, test.span, BinOp::Eq, expect, val);
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());
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),
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));
400 // actual = len(place)
401 self.cfg.push_assign(block, source_info,
402 &actual, Rvalue::Len(place.clone()));
405 let expected = self.push_usize(block, source_info, len);
407 // result = actual == expected OR result = actual < expected
408 self.cfg.push_assign(block, source_info, &result,
410 Operand::Move(actual),
411 Operand::Move(expected)));
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),
419 vec![true_bb, false_bb]
424 fn compare(&mut self,
426 fail_block: BasicBlock,
430 right: Operand<'tcx>) -> BasicBlock {
431 let bool_ty = self.hir.bool_ty();
432 let result = self.temp(bool_ty, span);
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));
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));
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
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
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
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>,
480 candidate: &Candidate<'pat, 'tcx>,
481 resulting_candidates: &mut [Vec<Candidate<'pat, 'tcx>>])
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
489 let tested_match_pair = candidate.match_pairs.iter()
491 .filter(|&(_, mp)| mp.place == *test_place)
493 let (match_pair_index, match_pair) = match tested_match_pair {
496 // We are not testing this place. Therefore, this
497 // candidate applies to ALL outcomes.
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);
509 self.candidate_after_variant_switch(match_pair_index,
514 resulting_candidates[variant_index].push(new_candidate);
517 (&TestKind::Switch { .. }, _) => false,
519 // If we are performing a switch over integers, then this informs integer
520 // equality, but nothing else.
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,
530 resulting_candidates[index].push(new_candidate);
533 (&TestKind::SwitchInt { .. }, _) => false,
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,
552 (Ordering::Less, _) => {
553 // test_len < pat_len. If $actual_len = test_len,
554 // then $actual_len < pat_len and we don't have
556 resulting_candidates[1].push(candidate.clone());
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.
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());
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,
581 resulting_candidates[0].push(
582 self.candidate_after_slice_test(match_pair_index,
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());
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());
603 (Ordering::Greater, &Some(_)) => {
604 // test_len < pat_len, and is therefore less
605 // strict. This can still go both ways.
611 (&TestKind::Eq { .. }, _) |
612 (&TestKind::Range { .. }, _) |
613 (&TestKind::Len { .. }, _) => {
614 // These are all binary tests.
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,
621 resulting_candidates[0].push(new_candidate);
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()
637 .filter(|&(index, _)| index != match_pair_index)
638 .map(|(_, mp)| mp.clone())
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,
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,
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];
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 =
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)
696 // In addition, we need all the other match pairs from the old candidate.
697 let other_match_pairs =
698 candidate.match_pairs.iter()
700 .filter(|&(index, _)| index != match_pair_index)
701 .map(|(_, mp)| mp.clone());
703 let all_match_pairs = consequent_match_pairs.chain(other_match_pairs).collect();
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,
718 fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
719 span_bug!(match_pair.pattern.span,
720 "simplifyable pattern found: {:?}",
725 fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
726 ty.is_integral() || ty.is_char() || ty.is_bool()