Skip to content

Commit d27c21c

Browse files
committed
Refactor for less allocation
1 parent 6c21a03 commit d27c21c

File tree

2 files changed

+69
-67
lines changed

2 files changed

+69
-67
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 61 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
612612
/// regardless of the signedness.
613613
/// For example, the pattern `-128...127i8` is encoded as `0..=255`.
614614
/// This makes comparisons and arithmetic on interval endpoints much more
615-
/// straightforward. See `encode` and `decode` for details.
615+
/// straightforward. See `signed_bias` for details.
616616
struct IntRange<'tcx> {
617617
pub range: RangeInclusive<u128>,
618618
pub ty: Ty<'tcx>,
@@ -660,6 +660,8 @@ impl<'tcx> IntRange<'tcx> {
660660
}
661661
}
662662

663+
// The return value of `signed_bias` should be
664+
// XORed with an endpoint to encode/decode it.
663665
fn signed_bias(tcx: TyCtxt<'_, 'tcx, 'tcx>, ty: Ty<'tcx>) -> u128 {
664666
match ty.sty {
665667
ty::TyInt(ity) => {
@@ -670,54 +672,52 @@ impl<'tcx> IntRange<'tcx> {
670672
}
671673
}
672674

673-
fn into_inner(self) -> (u128, u128) {
674-
self.range.into_inner()
675-
}
676-
}
677-
678-
/// Given a pattern in a `match` and a collection of ranges corresponding to the
679-
/// domain of values of a type (say, an integer), return a new collection of ranges
680-
/// corresponding to those ranges minus the ranges covered by the pattern.
681-
fn ranges_subtract_pattern<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
682-
pat_ctor: &Constructor<'tcx>,
683-
ranges: Vec<Constructor<'tcx>>)
684-
-> Vec<Constructor<'tcx>> {
685-
if let Some(pat_interval) = IntRange::from_ctor(cx.tcx, pat_ctor) {
675+
/// Given an `IntRange` corresponding to a pattern in a `match` and a collection of
676+
/// ranges corresponding to the domain of values of a type (say, an integer), return
677+
/// a new collection of ranges corresponding to the original ranges minus the ranges
678+
/// covered by the `IntRange`.
679+
fn subtract_from(self,
680+
tcx: TyCtxt<'_, 'tcx, 'tcx>,
681+
ranges: Vec<Constructor<'tcx>>)
682+
-> Vec<Constructor<'tcx>> {
683+
let ranges = ranges.into_iter().filter_map(|r| {
684+
IntRange::from_ctor(tcx, &r).map(|i| i.range)
685+
});
686+
// Convert a `RangeInclusive` to a `ConstantValue` or inclusive `ConstantRange`.
687+
let bias = IntRange::signed_bias(tcx, self.ty);
688+
let ty = ty::ParamEnv::empty().and(self.ty);
689+
let range_to_constant = |r: RangeInclusive<u128>| {
690+
let (lo, hi) = r.into_inner();
691+
if lo == hi {
692+
ConstantValue(ty::Const::from_bits(tcx, lo ^ bias, ty))
693+
} else {
694+
ConstantRange(ty::Const::from_bits(tcx, lo ^ bias, ty),
695+
ty::Const::from_bits(tcx, hi ^ bias, ty),
696+
RangeEnd::Included)
697+
}
698+
};
686699
let mut remaining_ranges = vec![];
687-
let mut ranges: Vec<_> = ranges.into_iter().filter_map(|r| {
688-
IntRange::from_ctor(cx.tcx, &r).map(|i| i.into_inner())
689-
}).collect();
690-
let ty = pat_interval.ty;
691-
let (pat_interval_lo, pat_interval_hi) = pat_interval.into_inner();
692-
for (subrange_lo, subrange_hi) in ranges {
693-
if pat_interval_lo > subrange_hi || subrange_lo > pat_interval_hi {
700+
let (lo, hi) = self.range.into_inner();
701+
for subrange in ranges {
702+
let (subrange_lo, subrange_hi) = subrange.into_inner();
703+
if lo > subrange_hi || subrange_lo > hi {
694704
// The pattern doesn't intersect with the subrange at all,
695705
// so the subrange remains untouched.
696-
remaining_ranges.push(subrange_lo..=subrange_hi);
706+
remaining_ranges.push(range_to_constant(subrange_lo..=subrange_hi));
697707
} else {
698-
if pat_interval_lo > subrange_lo {
708+
if lo > subrange_lo {
699709
// The pattern intersects an upper section of the
700710
// subrange, so a lower section will remain.
701-
remaining_ranges.push(subrange_lo..=(pat_interval_lo - 1));
711+
remaining_ranges.push(range_to_constant(subrange_lo..=(lo - 1)));
702712
}
703-
if pat_interval_hi < subrange_hi {
713+
if hi < subrange_hi {
704714
// The pattern intersects a lower section of the
705715
// subrange, so an upper section will remain.
706-
remaining_ranges.push((pat_interval_hi + 1)..=subrange_hi);
716+
remaining_ranges.push(range_to_constant((hi + 1)..=subrange_hi));
707717
}
708718
}
709719
}
710-
// Convert the remaining ranges from pairs to inclusive `ConstantRange`s.
711-
remaining_ranges.into_iter().map(|r| {
712-
let (lo, hi) = r.into_inner();
713-
let bias = IntRange::signed_bias(cx.tcx, ty);
714-
let ty = ty::ParamEnv::empty().and(ty);
715-
ConstantRange(ty::Const::from_bits(cx.tcx, lo ^ bias, ty),
716-
ty::Const::from_bits(cx.tcx, hi ^ bias, ty),
717-
RangeEnd::Included)
718-
}).collect()
719-
} else {
720-
ranges
720+
remaining_ranges
721721
}
722722
}
723723

@@ -818,38 +818,41 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
818818
// `missing_ctors` are those that should have appeared
819819
// as patterns in the `match` expression, but did not.
820820
let mut missing_ctors = vec![];
821-
'req: for req_ctor in &all_ctors {
822-
let mut sub_ctors = vec![req_ctor.clone()];
821+
for req_ctor in &all_ctors {
823822
// The only constructor patterns for which it is valid to
824823
// treat the values as constructors are ranges (see
825824
// `all_constructors` for details).
826825
let consider_value_constructors = value_constructors && match req_ctor {
827826
ConstantRange(..) => true,
828827
_ => false,
829828
};
830-
for used_ctor in &used_ctors {
831-
if consider_value_constructors {
832-
sub_ctors = ranges_subtract_pattern(cx, used_ctor, sub_ctors);
829+
if consider_value_constructors {
830+
let mut refined_ctors = vec![req_ctor.clone()];
831+
for used_ctor in &used_ctors {
832+
// Refine the required constructors for the type by subtracting
833+
// the range defined by the current constructor pattern.
834+
refined_ctors = match IntRange::from_ctor(cx.tcx, used_ctor) {
835+
Some(interval) => interval.subtract_from(cx.tcx, refined_ctors),
836+
None => refined_ctors,
837+
};
833838
// If the constructor patterns that have been considered so far
834839
// already cover the entire range of values, then we the
835840
// constructor is not missing, and we can move on to the next one.
836-
if sub_ctors.is_empty() {
837-
continue 'req;
838-
}
839-
} else {
840-
// If the pattern for the required constructor
841-
// appears in the `match`, then it is not missing,
842-
// and we can move on to the next one.
843-
if used_ctor == req_ctor {
844-
continue 'req;
841+
if refined_ctors.is_empty() {
842+
break;
845843
}
846844
}
845+
// If a constructor has not been matched, then it is missing.
846+
// We add `refined_ctors` instead of `req_ctor`, because then we can
847+
// provide more detailed error information about precisely which
848+
// ranges have been omitted.
849+
missing_ctors.extend(refined_ctors);
850+
} else {
851+
// A constructor is missing if it never appears in a `match` arm.
852+
if !used_ctors.iter().any(|used_ctor| used_ctor == req_ctor) {
853+
missing_ctors.push(req_ctor.clone());
854+
}
847855
}
848-
// If a constructor has not been matched, then it is missing.
849-
// We add `sub_ctors` instead of `req_ctor`, because then we can
850-
// provide more detailed error information about precisely which
851-
// ranges have been omitted.
852-
missing_ctors.extend(sub_ctors);
853856
}
854857

855858
// `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>,
968971
match ctor {
969972
// A constant range of length 1 is simply
970973
// a constant value.
971-
ConstantRange(lo, hi, _) if lo == hi => {
974+
ConstantValue(value) => {
972975
Witness(vec![Pattern {
973976
ty: pcx.ty,
974977
span: DUMMY_SP,
975-
kind: box PatternKind::Constant { value: lo },
978+
kind: box PatternKind::Constant { value },
976979
}])
977980
}
978981
// We always report missing intervals

src/librustc_mir/hair/pattern/mod.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -368,9 +368,14 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
368368
"lower range bound must be less than upper",
369369
);
370370
PatternKind::Wild
371-
},
372-
(RangeEnd::Included, None) |
373-
(RangeEnd::Included, Some(Ordering::Greater)) => {
371+
}
372+
(RangeEnd::Included, Some(Ordering::Equal)) => {
373+
PatternKind::Constant { value: lo }
374+
}
375+
(RangeEnd::Included, Some(Ordering::Less)) => {
376+
PatternKind::Range { lo, hi, end }
377+
}
378+
(RangeEnd::Included, _) => {
374379
let mut err = struct_span_err!(
375380
self.tcx.sess,
376381
lo_expr.span,
@@ -390,12 +395,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
390395
}
391396
err.emit();
392397
PatternKind::Wild
393-
},
394-
(RangeEnd::Included, Some(Ordering::Equal)) => {
395-
PatternKind::Constant { value: lo }
396-
}
397-
(RangeEnd::Included, Some(Ordering::Less)) => {
398-
PatternKind::Range { lo, hi, end }
399398
}
400399
}
401400
}

0 commit comments

Comments
 (0)