]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/matches/simplify.rs
14da8e9083892fb435c743a83573f5fc412f4839
[rust.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 `place @ pattern` means breaking it down
14 //! into bindings or other, simpler match pairs. For example:
15 //!
16 //! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
17 //! - `place @ x` can be simplified to `[]` by binding `x` to `place`
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::{Ascription, Binding, MatchPair, Candidate};
27 use hair::*;
28 use rustc::mir::*;
29
30 use std::mem;
31
32 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
33     pub fn simplify_candidate<'pat>(&mut self,
34                                     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(match_pair, candidate) {
43                     Ok(()) => {}
44                     Err(match_pair) => {
45                         candidate.match_pairs.push(match_pair);
46                         progress -= 1; // this one was not simplified
47                     }
48                 }
49             }
50             if progress == 0 {
51                 return block.unit(); // if we were not able to simplify any, done.
52             }
53         }
54     }
55
56     /// Tries to simplify `match_pair`, returning true if
57     /// successful. If successful, new match pairs and bindings will
58     /// have been pushed into the candidate. If no simplification is
59     /// possible, Err is returned and no changes are made to
60     /// candidate.
61     fn simplify_match_pair<'pat>(&mut self,
62                                  match_pair: MatchPair<'pat, 'tcx>,
63                                  candidate: &mut Candidate<'pat, 'tcx>)
64                                  -> Result<(), MatchPair<'pat, 'tcx>> {
65         match *match_pair.pattern.kind {
66             PatternKind::AscribeUserType { ref subpattern, user_ty } => {
67                 candidate.ascriptions.push(Ascription {
68                     span: match_pair.pattern.span,
69                     user_ty,
70                     source: match_pair.place.clone(),
71                 });
72
73                 candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
74
75                 Ok(())
76             }
77
78             PatternKind::Wild => {
79                 // nothing left to do
80                 Ok(())
81             }
82
83             PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
84                 candidate.bindings.push(Binding {
85                     name,
86                     mutability,
87                     span: match_pair.pattern.span,
88                     source: match_pair.place.clone(),
89                     var_id: var,
90                     var_ty: ty,
91                     binding_mode: mode,
92                 });
93
94                 if let Some(subpattern) = subpattern.as_ref() {
95                     // this is the `x @ P` case; have to keep matching against `P` now
96                     candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
97                 }
98
99                 Ok(())
100             }
101
102             PatternKind::Constant { .. } => {
103                 // FIXME normalize patterns when possible
104                 Err(match_pair)
105             }
106
107             PatternKind::Range { .. } => {
108                 Err(match_pair)
109             }
110
111             PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
112                 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
113                     // irrefutable
114                     self.prefix_slice_suffix(&mut candidate.match_pairs,
115                                              &match_pair.place,
116                                              prefix,
117                                              slice.as_ref(),
118                                              suffix);
119                     Ok(())
120                 } else {
121                     Err(match_pair)
122                 }
123             }
124
125             PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
126                 let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
127                     i == variant_index || {
128                         self.hir.tcx().features().never_type &&
129                         self.hir.tcx().features().exhaustive_patterns &&
130                         self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
131                     }
132                 });
133                 if irrefutable {
134                     let place = match_pair.place.downcast(adt_def, variant_index);
135                     candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
136                     Ok(())
137                 } else {
138                     Err(match_pair)
139                 }
140             },
141
142             PatternKind::Array { ref prefix, ref slice, ref suffix } => {
143                 self.prefix_slice_suffix(&mut candidate.match_pairs,
144                                          &match_pair.place,
145                                          prefix,
146                                          slice.as_ref(),
147                                          suffix);
148                 Ok(())
149             }
150
151             PatternKind::Leaf { ref subpatterns } => {
152                 // tuple struct, match subpats (if any)
153                 candidate.match_pairs
154                          .extend(self.field_match_pairs(match_pair.place, subpatterns));
155                 Ok(())
156             }
157
158             PatternKind::Deref { ref subpattern } => {
159                 let place = match_pair.place.deref();
160                 candidate.match_pairs.push(MatchPair::new(place, subpattern));
161                 Ok(())
162             }
163         }
164     }
165 }