]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/matches/simplify.rs
Allow a dirty MirBuilt for make_extern and make_method_extern
[rust.git] / src / librustc_mir / build / matches / simplify.rs
1 //! Simplifying Candidates
2 //!
3 //! *Simplifying* a match pair `place @ pattern` means breaking it down
4 //! into bindings or other, simpler match pairs. For example:
5 //!
6 //! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
7 //! - `place @ x` can be simplified to `[]` by binding `x` to `place`
8 //!
9 //! The `simplify_candidate` routine just repeatedly applies these
10 //! sort of simplifications until there is nothing left to
11 //! simplify. Match pairs cannot be simplified if they require some
12 //! sort of test: for example, testing which variant an enum is, or
13 //! testing a value against a constant.
14
15 use build::Builder;
16 use build::matches::{Ascription, Binding, MatchPair, Candidate};
17 use hair::*;
18 use rustc::ty;
19 use rustc::ty::layout::{Integer, IntegerExt, Size};
20 use syntax::attr::{SignedInt, UnsignedInt};
21 use rustc::hir::RangeEnd;
22
23 use std::mem;
24
25 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
26     pub fn simplify_candidate<'pat>(&mut self,
27                                     candidate: &mut Candidate<'pat, 'tcx>) {
28         // repeatedly simplify match pairs until fixed point is reached
29         loop {
30             let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
31             let mut changed = false;
32             for match_pair in match_pairs {
33                 match self.simplify_match_pair(match_pair, candidate) {
34                     Ok(()) => {
35                         changed = true;
36                     }
37                     Err(match_pair) => {
38                         candidate.match_pairs.push(match_pair);
39                     }
40                 }
41             }
42             if !changed {
43                 return; // if we were not able to simplify any, done.
44             }
45         }
46     }
47
48     /// Tries to simplify `match_pair`, returning true if
49     /// successful. If successful, new match pairs and bindings will
50     /// have been pushed into the candidate. If no simplification is
51     /// possible, Err is returned and no changes are made to
52     /// candidate.
53     fn simplify_match_pair<'pat>(&mut self,
54                                  match_pair: MatchPair<'pat, 'tcx>,
55                                  candidate: &mut Candidate<'pat, 'tcx>)
56                                  -> Result<(), MatchPair<'pat, 'tcx>> {
57         let tcx = self.hir.tcx();
58         match *match_pair.pattern.kind {
59             PatternKind::AscribeUserType {
60                 ref subpattern,
61                 variance,
62                 ref user_ty,
63                 user_ty_span
64             } => {
65                 // Apply the type ascription to the value at `match_pair.place`, which is the
66                 // value being matched, taking the variance field into account.
67                 candidate.ascriptions.push(Ascription {
68                     span: user_ty_span,
69                     user_ty: user_ty.clone(),
70                     source: match_pair.place.clone(),
71                     variance,
72                 });
73
74                 candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
75
76                 Ok(())
77             }
78
79             PatternKind::Wild => {
80                 // nothing left to do
81                 Ok(())
82             }
83
84             PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
85                 candidate.bindings.push(Binding {
86                     name,
87                     mutability,
88                     span: match_pair.pattern.span,
89                     source: match_pair.place.clone(),
90                     var_id: var,
91                     var_ty: ty,
92                     binding_mode: mode,
93                 });
94
95                 if let Some(subpattern) = subpattern.as_ref() {
96                     // this is the `x @ P` case; have to keep matching against `P` now
97                     candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
98                 }
99
100                 Ok(())
101             }
102
103             PatternKind::Constant { .. } => {
104                 // FIXME normalize patterns when possible
105                 Err(match_pair)
106             }
107
108             PatternKind::Range(PatternRange { lo, hi, ty, end }) => {
109                 let (range, bias) = match ty.sty {
110                     ty::Char => {
111                         (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
112                     }
113                     ty::Int(ity) => {
114                         // FIXME(49937): refactor these bit manipulations into interpret.
115                         let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
116                         let max = !0u128 >> (128 - size.bits());
117                         let bias = 1u128 << (size.bits() - 1);
118                         (Some((0, max, size)), bias)
119                     }
120                     ty::Uint(uty) => {
121                         // FIXME(49937): refactor these bit manipulations into interpret.
122                         let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
123                         let max = !0u128 >> (128 - size.bits());
124                         (Some((0, max, size)), 0)
125                     }
126                     _ => (None, 0),
127                 };
128                 if let Some((min, max, sz)) = range {
129                     if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
130                         // We want to compare ranges numerically, but the order of the bitwise
131                         // representation of signed integers does not match their numeric order.
132                         // Thus, to correct the ordering, we need to shift the range of signed
133                         // integers to correct the comparison. This is achieved by XORing with a
134                         // bias (see pattern/_match.rs for another pertinent example of this
135                         // pattern).
136                         let (lo, hi) = (lo ^ bias, hi ^ bias);
137                         if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
138                             // Irrefutable pattern match.
139                             return Ok(());
140                         }
141                     }
142                 }
143                 Err(match_pair)
144             }
145
146             PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
147                 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
148                     // irrefutable
149                     self.prefix_slice_suffix(&mut candidate.match_pairs,
150                                              &match_pair.place,
151                                              prefix,
152                                              slice.as_ref(),
153                                              suffix);
154                     Ok(())
155                 } else {
156                     Err(match_pair)
157                 }
158             }
159
160             PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
161                 let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
162                     i == variant_index || {
163                         self.hir.tcx().features().never_type &&
164                         self.hir.tcx().features().exhaustive_patterns &&
165                         self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
166                     }
167                 });
168                 if irrefutable {
169                     let place = match_pair.place.downcast(adt_def, variant_index);
170                     candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
171                     Ok(())
172                 } else {
173                     Err(match_pair)
174                 }
175             },
176
177             PatternKind::Array { ref prefix, ref slice, ref suffix } => {
178                 self.prefix_slice_suffix(&mut candidate.match_pairs,
179                                          &match_pair.place,
180                                          prefix,
181                                          slice.as_ref(),
182                                          suffix);
183                 Ok(())
184             }
185
186             PatternKind::Leaf { ref subpatterns } => {
187                 // tuple struct, match subpats (if any)
188                 candidate.match_pairs
189                          .extend(self.field_match_pairs(match_pair.place, subpatterns));
190                 Ok(())
191             }
192
193             PatternKind::Deref { ref subpattern } => {
194                 let place = match_pair.place.deref();
195                 candidate.match_pairs.push(MatchPair::new(place, subpattern));
196                 Ok(())
197             }
198         }
199     }
200 }