]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/build/matches/simplify.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / src / librustc_mir / build / matches / simplify.rs
CommitLineData
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
15use crate::build::Builder;
16use crate::build::matches::{Ascription, Binding, MatchPair, Candidate};
17use crate::hair::{self, *};
0731742a
XL
18use rustc::ty;
19use rustc::ty::layout::{Integer, IntegerExt, Size};
20use syntax::attr::{SignedInt, UnsignedInt};
21use rustc::hir::RangeEnd;
e9174d1e
SL
22
23use std::mem;
24
a7813a04 25impl<'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}