]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/matches/simplify.rs
Updating the instructions for when a tool breaks to use the new toolstate feature
[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 `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::*;
29 use rustc_data_structures::fx::FxHashMap;
30
31 use std::mem;
32
33 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
34     pub fn simplify_candidate<'pat>(&mut self,
35                                     block: BasicBlock,
36                                     candidate: &mut Candidate<'pat, 'tcx>)
37                                     -> BlockAnd<()> {
38         // repeatedly simplify match pairs until fixed point is reached
39         loop {
40             let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
41             let mut progress = match_pairs.len(); // count how many were simplified
42             for match_pair in match_pairs {
43                 match self.simplify_match_pair(match_pair, candidate) {
44                     Ok(()) => {}
45                     Err(match_pair) => {
46                         candidate.match_pairs.push(match_pair);
47                         progress -= 1; // this one was not simplified
48                     }
49                 }
50             }
51             if progress == 0 {
52                 return block.unit(); // if we were not able to simplify any, done.
53             }
54         }
55     }
56
57     /// Tries to simplify `match_pair`, returning true if
58     /// successful. If successful, new match pairs and bindings will
59     /// have been pushed into the candidate. If no simplification is
60     /// possible, Err is returned and no changes are made to
61     /// candidate.
62     fn simplify_match_pair<'pat>(&mut self,
63                                  match_pair: MatchPair<'pat, 'tcx>,
64                                  candidate: &mut Candidate<'pat, 'tcx>)
65                                  -> Result<(), MatchPair<'pat, 'tcx>> {
66         match *match_pair.pattern.kind {
67             PatternKind::Wild => {
68                 // nothing left to do
69                 Ok(())
70             }
71
72             PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
73                 candidate.bindings.push(Binding {
74                     name,
75                     mutability,
76                     span: match_pair.pattern.span,
77                     source: match_pair.lvalue.clone(),
78                     var_id: var,
79                     var_ty: ty,
80                     binding_mode: mode,
81                 });
82
83                 if let Some(subpattern) = subpattern.as_ref() {
84                     // this is the `x @ P` case; have to keep matching against `P` now
85                     candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
86                 }
87
88                 Ok(())
89             }
90
91             PatternKind::Constant { .. } => {
92                 // FIXME normalize patterns when possible
93                 Err(match_pair)
94             }
95
96             PatternKind::Range { .. } |
97             PatternKind::Slice { .. } => {
98                 Err(match_pair)
99             }
100
101             PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
102                 if self.hir.tcx().sess.features.borrow().never_type {
103                     let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
104                         i == variant_index || {
105                             let mut visited = FxHashMap::default();
106                             let node_set = v.uninhabited_from(&mut visited,
107                                                               self.hir.tcx(),
108                                                               substs,
109                                                               adt_def.adt_kind());
110                             !node_set.is_empty()
111                         }
112                     });
113                     if irrefutable {
114                         let lvalue = match_pair.lvalue.downcast(adt_def, variant_index);
115                         candidate.match_pairs.extend(self.field_match_pairs(lvalue, subpatterns));
116                         Ok(())
117                     } else {
118                         Err(match_pair)
119                     }
120                 } else {
121                     Err(match_pair)
122                 }
123             },
124
125             PatternKind::Array { ref prefix, ref slice, ref suffix } => {
126                 self.prefix_slice_suffix(&mut candidate.match_pairs,
127                                          &match_pair.lvalue,
128                                          prefix,
129                                          slice.as_ref(),
130                                          suffix);
131                 Ok(())
132             }
133
134             PatternKind::Leaf { ref subpatterns } => {
135                 // tuple struct, match subpats (if any)
136                 candidate.match_pairs
137                          .extend(self.field_match_pairs(match_pair.lvalue, subpatterns));
138                 Ok(())
139             }
140
141             PatternKind::Deref { ref subpattern } => {
142                 let lvalue = match_pair.lvalue.deref();
143                 candidate.match_pairs.push(MatchPair::new(lvalue, subpattern));
144                 Ok(())
145             }
146         }
147     }
148 }