use crate::build::Builder;
use crate::hair::{self, *};
use rustc::mir::interpret::truncate;
+use rustc::mir::Place;
use rustc::ty;
use rustc::ty::layout::{Integer, IntegerExt, Size};
+use rustc_attr::{SignedInt, UnsignedInt};
use rustc_hir::RangeEnd;
-use syntax::attr::{SignedInt, UnsignedInt};
+use smallvec::smallvec;
use std::mem;
impl<'a, 'tcx> Builder<'a, 'tcx> {
- crate fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) {
+ /// Simplify a candidate so that all match pairs require a test.
+ ///
+ /// This method will also split a candidate where the only match-pair is an
+ /// or-pattern into multiple candidates. This is so that
+ ///
+ /// match x {
+ /// 0 | 1 => { ... },
+ /// 2 | 3 => { ... },
+ /// }
+ ///
+ /// only generates a single switch. If this happens this method returns
+ /// `true`.
+ crate fn simplify_candidate<'pat>(&mut self, candidate: &mut Candidate<'pat, 'tcx>) -> bool {
// repeatedly simplify match pairs until fixed point is reached
loop {
let match_pairs = mem::take(&mut candidate.match_pairs);
+
+ if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, ref place }] =
+ *match_pairs
+ {
+ candidate.subcandidates = self.create_or_subcanidates(candidate, place, pats);
+ return true;
+ }
+
let mut changed = false;
for match_pair in match_pairs {
match self.simplify_match_pair(match_pair, candidate) {
}
}
if !changed {
- return; // if we were not able to simplify any, done.
+ // Move or-patterns to the end, because they can result in us
+ // creating additional candidates, so we want to test them as
+ // late as possible.
+ candidate
+ .match_pairs
+ .sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. }));
+ return false; // if we were not able to simplify any, done.
}
}
}
+ fn create_or_subcanidates<'pat>(
+ &mut self,
+ candidate: &Candidate<'pat, 'tcx>,
+ place: &Place<'tcx>,
+ pats: &'pat [Pat<'tcx>],
+ ) -> Vec<Candidate<'pat, 'tcx>> {
+ pats.iter()
+ .map(|pat| {
+ let mut candidate = Candidate {
+ span: pat.span,
+ has_guard: candidate.has_guard,
+ needs_otherwise_block: candidate.needs_otherwise_block,
+ match_pairs: smallvec![MatchPair { place: place.clone(), pattern: pat }],
+ bindings: vec![],
+ ascriptions: vec![],
+ subcandidates: vec![],
+ otherwise_block: None,
+ pre_binding_block: None,
+ next_candidate_pre_binding_block: None,
+ };
+ self.simplify_candidate(&mut candidate);
+ candidate
+ })
+ .collect()
+ }
+
/// Tries to simplify `match_pair`, returning `Ok(())` if
/// successful. If successful, new match pairs and bindings will
/// have been pushed into the candidate. If no simplification is
match *match_pair.pattern.kind {
PatKind::AscribeUserType {
ref subpattern,
- ascription: hair::pattern::Ascription { variance, ref user_ty, user_ty_span },
+ ascription: hair::pattern::Ascription { variance, user_ty, user_ty_span },
} => {
// Apply the type ascription to the value at `match_pair.place`, which is the
// value being matched, taking the variance field into account.
candidate.ascriptions.push(Ascription {
span: user_ty_span,
- user_ty: user_ty.clone(),
- source: match_pair.place.clone(),
+ user_ty: user_ty,
+ source: match_pair.place,
variance,
});
name,
mutability,
span: match_pair.pattern.span,
- source: match_pair.place.clone(),
+ source: match_pair.place,
var_id: var,
var_ty: ty,
binding_mode: mode,