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