Skip unnecessary comparison with half-open ranges
This commit is contained in:
parent
b6e4299415
commit
205319d962
2 changed files with 31 additions and 39 deletions
|
@ -958,22 +958,6 @@ impl<'tcx> PatRangeBoundary<'tcx> {
|
||||||
Self::NegInfinity | Self::PosInfinity => None,
|
Self::NegInfinity | Self::PosInfinity => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
|
||||||
pub fn to_const(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> mir::Const<'tcx> {
|
|
||||||
match self {
|
|
||||||
Self::Finite(value) => value,
|
|
||||||
Self::NegInfinity => {
|
|
||||||
// Unwrap is ok because the type is known to be numeric.
|
|
||||||
let c = ty.numeric_min_val(tcx).unwrap();
|
|
||||||
mir::Const::from_ty_const(c, tcx)
|
|
||||||
}
|
|
||||||
Self::PosInfinity => {
|
|
||||||
// Unwrap is ok because the type is known to be numeric.
|
|
||||||
let c = ty.numeric_max_val(tcx).unwrap();
|
|
||||||
mir::Const::from_ty_const(c, tcx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 {
|
pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 {
|
||||||
match self {
|
match self {
|
||||||
Self::Finite(value) => value.eval_bits(tcx, param_env),
|
Self::Finite(value) => value.eval_bits(tcx, param_env),
|
||||||
|
|
|
@ -291,33 +291,41 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
TestKind::Range(ref range) => {
|
TestKind::Range(ref range) => {
|
||||||
let lower_bound_success = self.cfg.start_new_block();
|
|
||||||
|
|
||||||
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
|
|
||||||
// FIXME: skip useless comparison when the range is half-open.
|
|
||||||
let lo = range.lo.to_const(range.ty, self.tcx);
|
|
||||||
let hi = range.hi.to_const(range.ty, self.tcx);
|
|
||||||
let lo = self.literal_operand(test.span, lo);
|
|
||||||
let hi = self.literal_operand(test.span, hi);
|
|
||||||
let val = Operand::Copy(place);
|
|
||||||
|
|
||||||
let [success, fail] = *target_blocks else {
|
let [success, fail] = *target_blocks else {
|
||||||
bug!("`TestKind::Range` should have two target blocks");
|
bug!("`TestKind::Range` should have two target blocks");
|
||||||
};
|
};
|
||||||
|
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
|
||||||
|
let val = Operand::Copy(place);
|
||||||
|
|
||||||
|
let intermediate_block = if !range.lo.is_finite() {
|
||||||
|
block
|
||||||
|
} else if !range.hi.is_finite() {
|
||||||
|
success
|
||||||
|
} else {
|
||||||
|
self.cfg.start_new_block()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(lo) = range.lo.as_finite() {
|
||||||
|
let lo = self.literal_operand(test.span, lo);
|
||||||
self.compare(
|
self.compare(
|
||||||
block,
|
block,
|
||||||
lower_bound_success,
|
intermediate_block,
|
||||||
fail,
|
fail,
|
||||||
source_info,
|
source_info,
|
||||||
BinOp::Le,
|
BinOp::Le,
|
||||||
lo,
|
lo,
|
||||||
val.clone(),
|
val.clone(),
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(hi) = range.hi.as_finite() {
|
||||||
|
let hi = self.literal_operand(test.span, hi);
|
||||||
let op = match range.end {
|
let op = match range.end {
|
||||||
RangeEnd::Included => BinOp::Le,
|
RangeEnd::Included => BinOp::Le,
|
||||||
RangeEnd::Excluded => BinOp::Lt,
|
RangeEnd::Excluded => BinOp::Lt,
|
||||||
};
|
};
|
||||||
self.compare(lower_bound_success, success, fail, source_info, op, val, hi);
|
self.compare(intermediate_block, success, fail, source_info, op, val, hi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TestKind::Len { len, op } => {
|
TestKind::Len { len, op } => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue