]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/build/matches/simplify.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_mir / build / matches / simplify.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 //! Simplifying Candidates
12 //!
13 //! *Simplifying* a match pair `lvalue @ pattern` means breaking it down
14 //! into bindings or other, simpler match pairs. For example:
15 //!
16 //! - `lvalue @ (P1, P2)` can be simplified to `[lvalue.0 @ P1, lvalue.1 @ P2]`
17 //! - `lvalue @ x` can be simplified to `[]` by binding `x` to `lvalue`
18 //!
19 //! The `simplify_candidate` routine just repeatedly applies these
20 //! sort of simplifications until there is nothing left to
21 //! simplify. Match pairs cannot be simplified if they require some
22 //! sort of test: for example, testing which variant an enum is, or
23 //! testing a value against a constant.
24
25 use build::{BlockAnd, BlockAndExtension, Builder};
26 use build::matches::{Binding, MatchPair, Candidate};
27 use hair::*;
28 use rustc::mir::repr::*;
29
30 use std::mem;
31
32 impl<'a,'tcx> Builder<'a,'tcx> {
33 pub fn simplify_candidate<'pat>(&mut self,
34 mut block: BasicBlock,
35 candidate: &mut Candidate<'pat, 'tcx>)
36 -> BlockAnd<()> {
37 // repeatedly simplify match pairs until fixed point is reached
38 loop {
39 let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
40 let mut progress = match_pairs.len(); // count how many were simplified
41 for match_pair in match_pairs {
42 match self.simplify_match_pair(block, match_pair, candidate) {
43 Ok(b) => {
44 block = b;
45 }
46 Err(match_pair) => {
47 candidate.match_pairs.push(match_pair);
48 progress -= 1; // this one was not simplified
49 }
50 }
51 }
52 if progress == 0 {
53 return block.unit(); // if we were not able to simplify any, done.
54 }
55 }
56 }
57
58 /// Tries to simplify `match_pair`, returning true if
59 /// successful. If successful, new match pairs and bindings will
60 /// have been pushed into the candidate. If no simplification is
61 /// possible, Err is returned and no changes are made to
62 /// candidate.
63 fn simplify_match_pair<'pat>(&mut self,
64 mut block: BasicBlock,
65 match_pair: MatchPair<'pat, 'tcx>,
66 candidate: &mut Candidate<'pat, 'tcx>)
67 -> Result<BasicBlock, MatchPair<'pat, 'tcx>> {
68 match *match_pair.pattern.kind {
69 PatternKind::Wild => {
70 // nothing left to do
71 Ok(block)
72 }
73
74 PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
75 candidate.bindings.push(Binding {
76 name: name,
77 mutability: mutability,
78 span: match_pair.pattern.span,
79 source: match_pair.lvalue.clone(),
80 var_id: var,
81 var_ty: ty,
82 binding_mode: mode,
83 });
84
85 if let Some(subpattern) = subpattern.as_ref() {
86 // this is the `x @ P` case; have to keep matching against `P` now
87 candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
88 }
89
90 Ok(block)
91 }
92
93 PatternKind::Constant { .. } => {
94 // FIXME normalize patterns when possible
95 Err(match_pair)
96 }
97
98 PatternKind::Range { .. } |
99 PatternKind::Variant { .. } => {
100 // cannot simplify, test is required
101 Err(match_pair)
102 }
103
104 PatternKind::Slice { .. } if !match_pair.slice_len_checked => {
105 Err(match_pair)
106 }
107
108 PatternKind::Array { ref prefix, ref slice, ref suffix } |
109 PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
110 unpack!(block = self.prefix_suffix_slice(&mut candidate.match_pairs,
111 block,
112 match_pair.lvalue.clone(),
113 prefix,
114 slice.as_ref(),
115 suffix));
116 Ok(block)
117 }
118
119 PatternKind::Leaf { ref subpatterns } => {
120 // tuple struct, match subpats (if any)
121 candidate.match_pairs
122 .extend(self.field_match_pairs(match_pair.lvalue, subpatterns));
123 Ok(block)
124 }
125
126 PatternKind::Deref { ref subpattern } => {
127 let lvalue = match_pair.lvalue.deref();
128 candidate.match_pairs.push(MatchPair::new(lvalue, subpattern));
129 Ok(block)
130 }
131 }
132 }
133 }