1 //! Simplifying Candidates
3 //! *Simplifying* a match pair `place @ pattern` means breaking it down
4 //! into bindings or other, simpler match pairs. For example:
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`
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.
15 use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
16 use crate::build::Builder;
17 use crate::hair::{self, *};
18 use rustc::mir::interpret::truncate;
20 use rustc::ty::layout::{Integer, IntegerExt, Size};
21 use rustc_attr::{SignedInt, UnsignedInt};
22 use rustc_hir::RangeEnd;
26 impl<'a, 'tcx> Builder<'a, 'tcx> {
27 crate fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) {
28 // repeatedly simplify match pairs until fixed point is reached
30 let match_pairs = mem::take(&mut candidate.match_pairs);
31 let mut changed = false;
32 for match_pair in match_pairs {
33 match self.simplify_match_pair(match_pair, candidate) {
38 candidate.match_pairs.push(match_pair);
43 return; // if we were not able to simplify any, done.
48 /// Tries to simplify `match_pair`, returning `Ok(())` 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
53 fn simplify_match_pair<'pat>(
55 match_pair: MatchPair<'pat, 'tcx>,
56 candidate: &mut Candidate<'pat, 'tcx>,
57 ) -> Result<(), MatchPair<'pat, 'tcx>> {
58 let tcx = self.hir.tcx();
59 match *match_pair.pattern.kind {
60 PatKind::AscribeUserType {
62 ascription: hair::pattern::Ascription { variance, user_ty, user_ty_span },
64 // Apply the type ascription to the value at `match_pair.place`, which is the
65 // value being matched, taking the variance field into account.
66 candidate.ascriptions.push(Ascription {
69 source: match_pair.place,
73 candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
83 PatKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
84 candidate.bindings.push(Binding {
87 span: match_pair.pattern.span,
88 source: match_pair.place,
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));
102 PatKind::Constant { .. } => {
103 // FIXME normalize patterns when possible
107 PatKind::Range(PatRange { lo, hi, end }) => {
108 let (range, bias) = match lo.ty.kind {
110 (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
113 let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
114 let max = truncate(u128::max_value(), size);
115 let bias = 1u128 << (size.bits() - 1);
116 (Some((0, max, size)), bias)
119 let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
120 let max = truncate(u128::max_value(), size);
121 (Some((0, max, size)), 0)
125 if let Some((min, max, sz)) = range {
126 if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
127 // We want to compare ranges numerically, but the order of the bitwise
128 // representation of signed integers does not match their numeric order.
129 // Thus, to correct the ordering, we need to shift the range of signed
130 // integers to correct the comparison. This is achieved by XORing with a
131 // bias (see pattern/_match.rs for another pertinent example of this
133 let (lo, hi) = (lo ^ bias, hi ^ bias);
134 if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
135 // Irrefutable pattern match.
143 PatKind::Slice { ref prefix, ref slice, ref suffix } => {
144 if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
146 self.prefix_slice_suffix(
147 &mut candidate.match_pairs,
159 PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
160 let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| {
161 i == variant_index || {
162 self.hir.tcx().features().exhaustive_patterns
164 .uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind())
167 }) && (adt_def.did.is_local()
168 || !adt_def.is_variant_list_non_exhaustive());
170 let place = tcx.mk_place_downcast(match_pair.place, adt_def, variant_index);
171 candidate.match_pairs.extend(self.field_match_pairs(place, subpatterns));
178 PatKind::Array { ref prefix, ref slice, ref suffix } => {
179 self.prefix_slice_suffix(
180 &mut candidate.match_pairs,
189 PatKind::Leaf { ref subpatterns } => {
190 // tuple struct, match subpats (if any)
191 candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
195 PatKind::Deref { ref subpattern } => {
196 let place = tcx.mk_place_deref(match_pair.place);
197 candidate.match_pairs.push(MatchPair::new(place, subpattern));
201 PatKind::Or { .. } => Err(match_pair),