Refactor for less allocation

This commit is contained in:
varkor 2018-05-28 20:53:20 +01:00
parent 6c21a0322c
commit d27c21c016
2 changed files with 69 additions and 67 deletions

View File

@ -612,7 +612,7 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
/// regardless of the signedness.
/// For example, the pattern `-128...127i8` is encoded as `0..=255`.
/// This makes comparisons and arithmetic on interval endpoints much more
/// straightforward. See `encode` and `decode` for details.
/// straightforward. See `signed_bias` for details.
struct IntRange<'tcx> {
pub range: RangeInclusive<u128>,
pub ty: Ty<'tcx>,
@ -660,6 +660,8 @@ impl<'tcx> IntRange<'tcx> {
}
}
// The return value of `signed_bias` should be
// XORed with an endpoint to encode/decode it.
fn signed_bias(tcx: TyCtxt<'_, 'tcx, 'tcx>, ty: Ty<'tcx>) -> u128 {
match ty.sty {
ty::TyInt(ity) => {
@ -670,54 +672,52 @@ impl<'tcx> IntRange<'tcx> {
}
}
fn into_inner(self) -> (u128, u128) {
self.range.into_inner()
}
}
/// Given a pattern in a `match` and a collection of ranges corresponding to the
/// domain of values of a type (say, an integer), return a new collection of ranges
/// corresponding to those ranges minus the ranges covered by the pattern.
fn ranges_subtract_pattern<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
pat_ctor: &Constructor<'tcx>,
ranges: Vec<Constructor<'tcx>>)
-> Vec<Constructor<'tcx>> {
if let Some(pat_interval) = IntRange::from_ctor(cx.tcx, pat_ctor) {
/// Given an `IntRange` corresponding to a pattern in a `match` and a collection of
/// ranges corresponding to the domain of values of a type (say, an integer), return
/// a new collection of ranges corresponding to the original ranges minus the ranges
/// covered by the `IntRange`.
fn subtract_from(self,
tcx: TyCtxt<'_, 'tcx, 'tcx>,
ranges: Vec<Constructor<'tcx>>)
-> Vec<Constructor<'tcx>> {
let ranges = ranges.into_iter().filter_map(|r| {
IntRange::from_ctor(tcx, &r).map(|i| i.range)
});
// Convert a `RangeInclusive` to a `ConstantValue` or inclusive `ConstantRange`.
let bias = IntRange::signed_bias(tcx, self.ty);
let ty = ty::ParamEnv::empty().and(self.ty);
let range_to_constant = |r: RangeInclusive<u128>| {
let (lo, hi) = r.into_inner();
if lo == hi {
ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty))
} else {
ConstantRange(ty::Const::from_bits(tcx, lo ^ bias, ty),
ty::Const::from_bits(tcx, hi ^ bias, ty),
RangeEnd::Included)
}
};
let mut remaining_ranges = vec![];
let mut ranges: Vec<_> = ranges.into_iter().filter_map(|r| {
IntRange::from_ctor(cx.tcx, &r).map(|i| i.into_inner())
}).collect();
let ty = pat_interval.ty;
let (pat_interval_lo, pat_interval_hi) = pat_interval.into_inner();
for (subrange_lo, subrange_hi) in ranges {
if pat_interval_lo > subrange_hi || subrange_lo > pat_interval_hi {
let (lo, hi) = self.range.into_inner();
for subrange in ranges {
let (subrange_lo, subrange_hi) = subrange.into_inner();
if lo > subrange_hi || subrange_lo > hi {
// The pattern doesn't intersect with the subrange at all,
// so the subrange remains untouched.
remaining_ranges.push(subrange_lo..=subrange_hi);
remaining_ranges.push(range_to_constant(subrange_lo..=subrange_hi));
} else {
if pat_interval_lo > subrange_lo {
if lo > subrange_lo {
// The pattern intersects an upper section of the
// subrange, so a lower section will remain.
remaining_ranges.push(subrange_lo..=(pat_interval_lo - 1));
remaining_ranges.push(range_to_constant(subrange_lo..=(lo - 1)));
}
if pat_interval_hi < subrange_hi {
if hi < subrange_hi {
// The pattern intersects a lower section of the
// subrange, so an upper section will remain.
remaining_ranges.push((pat_interval_hi + 1)..=subrange_hi);
remaining_ranges.push(range_to_constant((hi + 1)..=subrange_hi));
}
}
}
// Convert the remaining ranges from pairs to inclusive `ConstantRange`s.
remaining_ranges.into_iter().map(|r| {
let (lo, hi) = r.into_inner();
let bias = IntRange::signed_bias(cx.tcx, ty);
let ty = ty::ParamEnv::empty().and(ty);
ConstantRange(ty::Const::from_bits(cx.tcx, lo ^ bias, ty),
ty::Const::from_bits(cx.tcx, hi ^ bias, ty),
RangeEnd::Included)
}).collect()
} else {
ranges
remaining_ranges
}
}
@ -818,8 +818,7 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
// `missing_ctors` are those that should have appeared
// as patterns in the `match` expression, but did not.
let mut missing_ctors = vec![];
'req: for req_ctor in &all_ctors {
let mut sub_ctors = vec![req_ctor.clone()];
for req_ctor in &all_ctors {
// The only constructor patterns for which it is valid to
// treat the values as constructors are ranges (see
// `all_constructors` for details).
@ -827,29 +826,33 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
ConstantRange(..) => true,
_ => false,
};
for used_ctor in &used_ctors {
if consider_value_constructors {
sub_ctors = ranges_subtract_pattern(cx, used_ctor, sub_ctors);
if consider_value_constructors {
let mut refined_ctors = vec![req_ctor.clone()];
for used_ctor in &used_ctors {
// Refine the required constructors for the type by subtracting
// the range defined by the current constructor pattern.
refined_ctors = match IntRange::from_ctor(cx.tcx, used_ctor) {
Some(interval) => interval.subtract_from(cx.tcx, refined_ctors),
None => refined_ctors,
};
// If the constructor patterns that have been considered so far
// already cover the entire range of values, then we the
// constructor is not missing, and we can move on to the next one.
if sub_ctors.is_empty() {
continue 'req;
}
} else {
// If the pattern for the required constructor
// appears in the `match`, then it is not missing,
// and we can move on to the next one.
if used_ctor == req_ctor {
continue 'req;
if refined_ctors.is_empty() {
break;
}
}
// If a constructor has not been matched, then it is missing.
// We add `refined_ctors` instead of `req_ctor`, because then we can
// provide more detailed error information about precisely which
// ranges have been omitted.
missing_ctors.extend(refined_ctors);
} else {
// A constructor is missing if it never appears in a `match` arm.
if !used_ctors.iter().any(|used_ctor| used_ctor == req_ctor) {
missing_ctors.push(req_ctor.clone());
}
}
// If a constructor has not been matched, then it is missing.
// We add `sub_ctors` instead of `req_ctor`, because then we can
// provide more detailed error information about precisely which
// ranges have been omitted.
missing_ctors.extend(sub_ctors);
}
// `missing_ctors` is the set of constructors from the same type as the
@ -968,11 +971,11 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
match ctor {
// A constant range of length 1 is simply
// a constant value.
ConstantRange(lo, hi, _) if lo == hi => {
ConstantValue(value) => {
Witness(vec![Pattern {
ty: pcx.ty,
span: DUMMY_SP,
kind: box PatternKind::Constant { value: lo },
kind: box PatternKind::Constant { value },
}])
}
// We always report missing intervals

View File

@ -368,9 +368,14 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
"lower range bound must be less than upper",
);
PatternKind::Wild
},
(RangeEnd::Included, None) |
(RangeEnd::Included, Some(Ordering::Greater)) => {
}
(RangeEnd::Included, Some(Ordering::Equal)) => {
PatternKind::Constant { value: lo }
}
(RangeEnd::Included, Some(Ordering::Less)) => {
PatternKind::Range { lo, hi, end }
}
(RangeEnd::Included, _) => {
let mut err = struct_span_err!(
self.tcx.sess,
lo_expr.span,
@ -390,12 +395,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
}
err.emit();
PatternKind::Wild
},
(RangeEnd::Included, Some(Ordering::Equal)) => {
PatternKind::Constant { value: lo }
}
(RangeEnd::Included, Some(Ordering::Less)) => {
PatternKind::Range { lo, hi, end }
}
}
}