Evaluate float consts eagerly
This commit is contained in:
parent
56ada88e7e
commit
fac50e8fb3
@ -50,6 +50,7 @@
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_hir::{HirId, RangeEnd};
|
||||
use rustc_index::Idx;
|
||||
@ -65,7 +66,6 @@
|
||||
use self::Constructor::*;
|
||||
use self::SliceKind::*;
|
||||
|
||||
use super::compare_const_vals;
|
||||
use super::usefulness::{MatchCheckCtxt, PatCtxt};
|
||||
use crate::errors::{Overlap, OverlappingRangeEndpoints};
|
||||
|
||||
@ -619,7 +619,8 @@ pub(super) enum Constructor<'tcx> {
|
||||
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
||||
IntRange(IntRange),
|
||||
/// Ranges of floating-point literal values (`2.0..=5.2`).
|
||||
FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd),
|
||||
F32Range(IeeeFloat<SingleS>, IeeeFloat<SingleS>, RangeEnd),
|
||||
F64Range(IeeeFloat<DoubleS>, IeeeFloat<DoubleS>, RangeEnd),
|
||||
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
|
||||
Str(mir::Const<'tcx>),
|
||||
/// Array and slice patterns.
|
||||
@ -634,7 +635,9 @@ pub(super) enum Constructor<'tcx> {
|
||||
/// Stands for constructors that are not seen in the matrix, as explained in the documentation
|
||||
/// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns`
|
||||
/// lint.
|
||||
Missing { nonexhaustive_enum_missing_real_variants: bool },
|
||||
Missing {
|
||||
nonexhaustive_enum_missing_real_variants: bool,
|
||||
},
|
||||
/// Wildcard pattern.
|
||||
Wildcard,
|
||||
/// Or-pattern.
|
||||
@ -722,7 +725,8 @@ pub(super) fn arity(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> usize {
|
||||
},
|
||||
Slice(slice) => slice.arity(),
|
||||
Str(..)
|
||||
| FloatRange(..)
|
||||
| F32Range(..)
|
||||
| F64Range(..)
|
||||
| IntRange(..)
|
||||
| NonExhaustive
|
||||
| Opaque
|
||||
@ -795,21 +799,21 @@ pub(super) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self
|
||||
(Variant(self_id), Variant(other_id)) => self_id == other_id,
|
||||
|
||||
(IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range),
|
||||
(
|
||||
FloatRange(self_from, self_to, self_end),
|
||||
FloatRange(other_from, other_to, other_end),
|
||||
) => {
|
||||
match (
|
||||
compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env),
|
||||
compare_const_vals(pcx.cx.tcx, *self_from, *other_from, pcx.cx.param_env),
|
||||
) {
|
||||
(Some(to), Some(from)) => {
|
||||
(from == Ordering::Greater || from == Ordering::Equal)
|
||||
&& (to == Ordering::Less
|
||||
|| (other_end == self_end && to == Ordering::Equal))
|
||||
(F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => {
|
||||
self_from.ge(other_from)
|
||||
&& match self_to.partial_cmp(other_to) {
|
||||
Some(Ordering::Less) => true,
|
||||
Some(Ordering::Equal) => other_end == self_end,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
(F64Range(self_from, self_to, self_end), F64Range(other_from, other_to, other_end)) => {
|
||||
self_from.ge(other_from)
|
||||
&& match self_to.partial_cmp(other_to) {
|
||||
Some(Ordering::Less) => true,
|
||||
Some(Ordering::Equal) => other_end == self_end,
|
||||
_ => false,
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
(Str(self_val), Str(other_val)) => {
|
||||
// FIXME Once valtrees are available we can directly use the bytes
|
||||
@ -859,7 +863,7 @@ fn is_covered_by_any<'p>(
|
||||
.any(|other| slice.is_covered_by(other)),
|
||||
// This constructor is never covered by anything else
|
||||
NonExhaustive => false,
|
||||
Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard | Or => {
|
||||
Str(..) | F32Range(..) | F64Range(..) | Opaque | Missing { .. } | Wildcard | Or => {
|
||||
span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self)
|
||||
}
|
||||
}
|
||||
@ -1203,7 +1207,8 @@ pub(super) fn wildcards(pcx: &PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'
|
||||
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
|
||||
},
|
||||
Str(..)
|
||||
| FloatRange(..)
|
||||
| F32Range(..)
|
||||
| F64Range(..)
|
||||
| IntRange(..)
|
||||
| NonExhaustive
|
||||
| Opaque
|
||||
@ -1348,8 +1353,19 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
|
||||
fields = Fields::empty();
|
||||
} else {
|
||||
match pat.ty.kind() {
|
||||
ty::Float(_) => {
|
||||
ctor = FloatRange(*value, *value, RangeEnd::Included);
|
||||
ty::Float(float_ty) => {
|
||||
let bits = value.eval_bits(cx.tcx, cx.param_env);
|
||||
use rustc_apfloat::Float;
|
||||
ctor = match float_ty {
|
||||
ty::FloatTy::F32 => {
|
||||
let value = rustc_apfloat::ieee::Single::from_bits(bits);
|
||||
F32Range(value, value, RangeEnd::Included)
|
||||
}
|
||||
ty::FloatTy::F64 => {
|
||||
let value = rustc_apfloat::ieee::Double::from_bits(bits);
|
||||
F64Range(value, value, RangeEnd::Included)
|
||||
}
|
||||
};
|
||||
fields = Fields::empty();
|
||||
}
|
||||
ty::Ref(_, t, _) if t.is_str() => {
|
||||
@ -1376,17 +1392,25 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
|
||||
}
|
||||
}
|
||||
&PatKind::Range(box PatRange { lo, hi, end }) => {
|
||||
use rustc_apfloat::Float;
|
||||
let ty = lo.ty();
|
||||
ctor = if let Some(int_range) = IntRange::from_range(
|
||||
cx.tcx,
|
||||
lo.eval_bits(cx.tcx, cx.param_env),
|
||||
hi.eval_bits(cx.tcx, cx.param_env),
|
||||
ty,
|
||||
&end,
|
||||
) {
|
||||
IntRange(int_range)
|
||||
} else {
|
||||
FloatRange(lo, hi, end)
|
||||
let lo = lo.eval_bits(cx.tcx, cx.param_env);
|
||||
let hi = hi.eval_bits(cx.tcx, cx.param_env);
|
||||
ctor = match ty.kind() {
|
||||
ty::Char | ty::Int(_) | ty::Uint(_) => {
|
||||
IntRange(IntRange::from_range(cx.tcx, lo, hi, ty, &end).unwrap())
|
||||
}
|
||||
ty::Float(ty::FloatTy::F32) => {
|
||||
let lo = rustc_apfloat::ieee::Single::from_bits(lo);
|
||||
let hi = rustc_apfloat::ieee::Single::from_bits(hi);
|
||||
F32Range(lo, hi, *end)
|
||||
}
|
||||
ty::Float(ty::FloatTy::F64) => {
|
||||
let lo = rustc_apfloat::ieee::Double::from_bits(lo);
|
||||
let hi = rustc_apfloat::ieee::Double::from_bits(hi);
|
||||
F64Range(lo, hi, *end)
|
||||
}
|
||||
_ => bug!("invalid type for range pattern: {}", ty),
|
||||
};
|
||||
fields = Fields::empty();
|
||||
}
|
||||
@ -1491,14 +1515,13 @@ pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
|
||||
}
|
||||
}
|
||||
&Str(value) => PatKind::Constant { value },
|
||||
&FloatRange(lo, hi, end) => PatKind::Range(Box::new(PatRange { lo, hi, end })),
|
||||
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
|
||||
Wildcard | NonExhaustive => PatKind::Wild,
|
||||
Missing { .. } => bug!(
|
||||
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
|
||||
`Missing` should have been processed in `apply_constructors`"
|
||||
),
|
||||
Opaque | Or => {
|
||||
F32Range(..) | F64Range(..) | Opaque | Or => {
|
||||
bug!("can't convert to pattern: {:?}", self)
|
||||
}
|
||||
};
|
||||
@ -1673,11 +1696,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
&FloatRange(lo, hi, end) => {
|
||||
write!(f, "{lo}")?;
|
||||
write!(f, "{end}")?;
|
||||
write!(f, "{hi}")
|
||||
}
|
||||
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
||||
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
|
||||
IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0`
|
||||
Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty),
|
||||
Or => {
|
||||
|
@ -1,19 +1,45 @@
|
||||
#![feature(exclusive_range_pattern)]
|
||||
#![allow(illegal_floating_point_literal_pattern)]
|
||||
#![deny(unreachable_patterns)]
|
||||
|
||||
fn main() {
|
||||
match 0.0 {
|
||||
0.0..=1.0 => {}
|
||||
_ => {} // ok
|
||||
0.0..=1.0 => {}
|
||||
_ => {} // ok
|
||||
}
|
||||
|
||||
match 0.0 { //~ ERROR non-exhaustive patterns
|
||||
0.0..=1.0 => {}
|
||||
match 0.0 {
|
||||
//~^ ERROR non-exhaustive patterns
|
||||
0.0..=1.0 => {}
|
||||
}
|
||||
|
||||
match 1.0f64 {
|
||||
0.01f64 ..= 6.5f64 => {}
|
||||
0.02f64 => {} //~ ERROR unreachable pattern
|
||||
_ => {}
|
||||
0.01f64..=6.5f64 => {}
|
||||
0.005f64 => {}
|
||||
0.01f64 => {} //~ ERROR unreachable pattern
|
||||
0.02f64 => {} //~ ERROR unreachable pattern
|
||||
6.5f64 => {} //~ ERROR unreachable pattern
|
||||
6.6f64 => {}
|
||||
1.0f64..=4.0f64 => {} //~ ERROR unreachable pattern
|
||||
5.0f64..=7.0f64 => {}
|
||||
_ => {}
|
||||
};
|
||||
match 1.0f64 {
|
||||
0.01f64..6.5f64 => {}
|
||||
6.5f64 => {} // this is reachable
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match 1.0f32 {
|
||||
0.01f32..=6.5f32 => {}
|
||||
0.01f32 => {} //~ ERROR unreachable pattern
|
||||
0.02f32 => {} //~ ERROR unreachable pattern
|
||||
6.5f32 => {} //~ ERROR unreachable pattern
|
||||
_ => {}
|
||||
};
|
||||
match 1.0f32 {
|
||||
0.01f32..6.5f32 => {}
|
||||
6.5f32 => {} // this is reachable
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0004]: non-exhaustive patterns: `_` not covered
|
||||
--> $DIR/floats.rs:10:11
|
||||
--> $DIR/floats.rs:11:11
|
||||
|
|
||||
LL | match 0.0 {
|
||||
| ^^^ pattern `_` not covered
|
||||
@ -7,22 +7,58 @@ LL | match 0.0 {
|
||||
= note: the matched value is of type `f64`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
||||
|
|
||||
LL ~ 0.0..=1.0 => {},
|
||||
LL + _ => todo!()
|
||||
LL ~ 0.0..=1.0 => {},
|
||||
LL + _ => todo!()
|
||||
|
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/floats.rs:16:7
|
||||
--> $DIR/floats.rs:19:9
|
||||
|
|
||||
LL | 0.02f64 => {}
|
||||
| ^^^^^^^
|
||||
LL | 0.01f64 => {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/floats.rs:2:9
|
||||
--> $DIR/floats.rs:3:9
|
||||
|
|
||||
LL | #![deny(unreachable_patterns)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: unreachable pattern
|
||||
--> $DIR/floats.rs:20:9
|
||||
|
|
||||
LL | 0.02f64 => {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/floats.rs:21:9
|
||||
|
|
||||
LL | 6.5f64 => {}
|
||||
| ^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/floats.rs:23:9
|
||||
|
|
||||
LL | 1.0f64..=4.0f64 => {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/floats.rs:35:9
|
||||
|
|
||||
LL | 0.01f32 => {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/floats.rs:36:9
|
||||
|
|
||||
LL | 0.02f32 => {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: unreachable pattern
|
||||
--> $DIR/floats.rs:37:9
|
||||
|
|
||||
LL | 6.5f32 => {}
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
||||
|
Loading…
Reference in New Issue
Block a user