Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize integral pattern matching #65089

Merged
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 26 additions & 33 deletions src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1625,36 +1625,6 @@ fn split_grouped_constructors<'p, 'tcx>(
split_ctors
}

/// Checks whether there exists any shared value in either `ctor` or `pat` by intersecting them.
fn constructor_intersects_pattern<'p, 'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
ctor: &Constructor<'tcx>,
pat: &'p Pat<'tcx>,
) -> Option<SmallVec<[&'p Pat<'tcx>; 2]>> {
if should_treat_range_exhaustively(tcx, ctor) {
match (IntRange::from_ctor(tcx, param_env, ctor), IntRange::from_pat(tcx, param_env, pat)) {
(Some(ctor), Some(pat)) => {
ctor.intersection(&pat).map(|_| {
let (pat_lo, pat_hi) = pat.range.into_inner();
let (ctor_lo, ctor_hi) = ctor.range.into_inner();
assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
smallvec![]
})
}
_ => None,
}
} else {
// Fallback for non-ranges and ranges that involve floating-point numbers, which are not
// conveniently handled by `IntRange`. For these cases, the constructor may not be a range
// so intersection actually devolves into being covered by the pattern.
match constructor_covered_by_range(tcx, param_env, ctor, pat) {
Ok(true) => Some(smallvec![]),
Ok(false) | Err(ErrorReported) => None,
}
}
}

fn constructor_covered_by_range<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
Expand Down Expand Up @@ -1845,9 +1815,32 @@ fn specialize<'p, 'a: 'p, 'tcx>(
PatKind::Constant { .. } |
PatKind::Range { .. } => {
// If the constructor is a:
// Single value: add a row if the pattern contains the constructor.
// Range: add a row if the constructor intersects the pattern.
constructor_intersects_pattern(cx.tcx, cx.param_env, constructor, pat)
// - Single value: add a row if the pattern contains the constructor.
// - Range: add a row if the constructor intersects the pattern.
if should_treat_range_exhaustively(cx.tcx, constructor) {
match (IntRange::from_ctor(cx.tcx, cx.param_env, constructor),
IntRange::from_pat(cx.tcx, cx.param_env, pat)) {
(Some(ctor), Some(pat)) => {
ctor.intersection(&pat).map(|_| {
let (pat_lo, pat_hi) = pat.range.into_inner();
let (ctor_lo, ctor_hi) = ctor.range.into_inner();
assert!(pat_lo <= ctor_lo && ctor_hi <= pat_hi);
smallvec![]
})
}
_ => None,
}
} else {
// Fallback for non-ranges and ranges that involve
// floating-point numbers, which are not conveniently handled
// by `IntRange`. For these cases, the constructor may not be a
// range so intersection actually devolves into being covered
// by the pattern.
match constructor_covered_by_range(cx.tcx, cx.param_env, constructor, pat) {
Ok(true) => Some(smallvec![]),
Ok(false) | Err(ErrorReported) => None,
}
}
}

PatKind::Array { ref prefix, ref slice, ref suffix } |
Expand Down