Skip to content

Commit fac50e8

Browse files
committed
Evaluate float consts eagerly
1 parent 56ada88 commit fac50e8

File tree

3 files changed

+136
-54
lines changed

3 files changed

+136
-54
lines changed

compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs

+59-39
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ use std::ops::RangeInclusive;
5050

5151
use smallvec::{smallvec, SmallVec};
5252

53+
use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
5354
use rustc_data_structures::captures::Captures;
5455
use rustc_hir::{HirId, RangeEnd};
5556
use rustc_index::Idx;
@@ -65,7 +66,6 @@ use rustc_target::abi::{FieldIdx, Integer, Size, VariantIdx, FIRST_VARIANT};
6566
use self::Constructor::*;
6667
use self::SliceKind::*;
6768

68-
use super::compare_const_vals;
6969
use super::usefulness::{MatchCheckCtxt, PatCtxt};
7070
use crate::errors::{Overlap, OverlappingRangeEndpoints};
7171

@@ -619,7 +619,8 @@ pub(super) enum Constructor<'tcx> {
619619
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
620620
IntRange(IntRange),
621621
/// Ranges of floating-point literal values (`2.0..=5.2`).
622-
FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd),
622+
F32Range(IeeeFloat<SingleS>, IeeeFloat<SingleS>, RangeEnd),
623+
F64Range(IeeeFloat<DoubleS>, IeeeFloat<DoubleS>, RangeEnd),
623624
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
624625
Str(mir::Const<'tcx>),
625626
/// Array and slice patterns.
@@ -634,7 +635,9 @@ pub(super) enum Constructor<'tcx> {
634635
/// Stands for constructors that are not seen in the matrix, as explained in the documentation
635636
/// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns`
636637
/// lint.
637-
Missing { nonexhaustive_enum_missing_real_variants: bool },
638+
Missing {
639+
nonexhaustive_enum_missing_real_variants: bool,
640+
},
638641
/// Wildcard pattern.
639642
Wildcard,
640643
/// Or-pattern.
@@ -722,7 +725,8 @@ impl<'tcx> Constructor<'tcx> {
722725
},
723726
Slice(slice) => slice.arity(),
724727
Str(..)
725-
| FloatRange(..)
728+
| F32Range(..)
729+
| F64Range(..)
726730
| IntRange(..)
727731
| NonExhaustive
728732
| Opaque
@@ -795,21 +799,21 @@ impl<'tcx> Constructor<'tcx> {
795799
(Variant(self_id), Variant(other_id)) => self_id == other_id,
796800

797801
(IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range),
798-
(
799-
FloatRange(self_from, self_to, self_end),
800-
FloatRange(other_from, other_to, other_end),
801-
) => {
802-
match (
803-
compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env),
804-
compare_const_vals(pcx.cx.tcx, *self_from, *other_from, pcx.cx.param_env),
805-
) {
806-
(Some(to), Some(from)) => {
807-
(from == Ordering::Greater || from == Ordering::Equal)
808-
&& (to == Ordering::Less
809-
|| (other_end == self_end && to == Ordering::Equal))
802+
(F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => {
803+
self_from.ge(other_from)
804+
&& match self_to.partial_cmp(other_to) {
805+
Some(Ordering::Less) => true,
806+
Some(Ordering::Equal) => other_end == self_end,
807+
_ => false,
808+
}
809+
}
810+
(F64Range(self_from, self_to, self_end), F64Range(other_from, other_to, other_end)) => {
811+
self_from.ge(other_from)
812+
&& match self_to.partial_cmp(other_to) {
813+
Some(Ordering::Less) => true,
814+
Some(Ordering::Equal) => other_end == self_end,
815+
_ => false,
810816
}
811-
_ => false,
812-
}
813817
}
814818
(Str(self_val), Str(other_val)) => {
815819
// FIXME Once valtrees are available we can directly use the bytes
@@ -859,7 +863,7 @@ impl<'tcx> Constructor<'tcx> {
859863
.any(|other| slice.is_covered_by(other)),
860864
// This constructor is never covered by anything else
861865
NonExhaustive => false,
862-
Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard | Or => {
866+
Str(..) | F32Range(..) | F64Range(..) | Opaque | Missing { .. } | Wildcard | Or => {
863867
span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self)
864868
}
865869
}
@@ -1203,7 +1207,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12031207
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
12041208
},
12051209
Str(..)
1206-
| FloatRange(..)
1210+
| F32Range(..)
1211+
| F64Range(..)
12071212
| IntRange(..)
12081213
| NonExhaustive
12091214
| Opaque
@@ -1348,8 +1353,19 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13481353
fields = Fields::empty();
13491354
} else {
13501355
match pat.ty.kind() {
1351-
ty::Float(_) => {
1352-
ctor = FloatRange(*value, *value, RangeEnd::Included);
1356+
ty::Float(float_ty) => {
1357+
let bits = value.eval_bits(cx.tcx, cx.param_env);
1358+
use rustc_apfloat::Float;
1359+
ctor = match float_ty {
1360+
ty::FloatTy::F32 => {
1361+
let value = rustc_apfloat::ieee::Single::from_bits(bits);
1362+
F32Range(value, value, RangeEnd::Included)
1363+
}
1364+
ty::FloatTy::F64 => {
1365+
let value = rustc_apfloat::ieee::Double::from_bits(bits);
1366+
F64Range(value, value, RangeEnd::Included)
1367+
}
1368+
};
13531369
fields = Fields::empty();
13541370
}
13551371
ty::Ref(_, t, _) if t.is_str() => {
@@ -1376,17 +1392,25 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13761392
}
13771393
}
13781394
&PatKind::Range(box PatRange { lo, hi, end }) => {
1395+
use rustc_apfloat::Float;
13791396
let ty = lo.ty();
1380-
ctor = if let Some(int_range) = IntRange::from_range(
1381-
cx.tcx,
1382-
lo.eval_bits(cx.tcx, cx.param_env),
1383-
hi.eval_bits(cx.tcx, cx.param_env),
1384-
ty,
1385-
&end,
1386-
) {
1387-
IntRange(int_range)
1388-
} else {
1389-
FloatRange(lo, hi, end)
1397+
let lo = lo.eval_bits(cx.tcx, cx.param_env);
1398+
let hi = hi.eval_bits(cx.tcx, cx.param_env);
1399+
ctor = match ty.kind() {
1400+
ty::Char | ty::Int(_) | ty::Uint(_) => {
1401+
IntRange(IntRange::from_range(cx.tcx, lo, hi, ty, &end).unwrap())
1402+
}
1403+
ty::Float(ty::FloatTy::F32) => {
1404+
let lo = rustc_apfloat::ieee::Single::from_bits(lo);
1405+
let hi = rustc_apfloat::ieee::Single::from_bits(hi);
1406+
F32Range(lo, hi, *end)
1407+
}
1408+
ty::Float(ty::FloatTy::F64) => {
1409+
let lo = rustc_apfloat::ieee::Double::from_bits(lo);
1410+
let hi = rustc_apfloat::ieee::Double::from_bits(hi);
1411+
F64Range(lo, hi, *end)
1412+
}
1413+
_ => bug!("invalid type for range pattern: {}", ty),
13901414
};
13911415
fields = Fields::empty();
13921416
}
@@ -1491,14 +1515,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14911515
}
14921516
}
14931517
&Str(value) => PatKind::Constant { value },
1494-
&FloatRange(lo, hi, end) => PatKind::Range(Box::new(PatRange { lo, hi, end })),
14951518
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
14961519
Wildcard | NonExhaustive => PatKind::Wild,
14971520
Missing { .. } => bug!(
14981521
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
14991522
`Missing` should have been processed in `apply_constructors`"
15001523
),
1501-
Opaque | Or => {
1524+
F32Range(..) | F64Range(..) | Opaque | Or => {
15021525
bug!("can't convert to pattern: {:?}", self)
15031526
}
15041527
};
@@ -1673,11 +1696,8 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
16731696
}
16741697
write!(f, "]")
16751698
}
1676-
&FloatRange(lo, hi, end) => {
1677-
write!(f, "{lo}")?;
1678-
write!(f, "{end}")?;
1679-
write!(f, "{hi}")
1680-
}
1699+
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
1700+
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
16811701
IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0`
16821702
Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty),
16831703
Or => {

tests/ui/pattern/usefulness/floats.rs

+33-7
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,45 @@
1+
#![feature(exclusive_range_pattern)]
12
#![allow(illegal_floating_point_literal_pattern)]
23
#![deny(unreachable_patterns)]
34

45
fn main() {
56
match 0.0 {
6-
0.0..=1.0 => {}
7-
_ => {} // ok
7+
0.0..=1.0 => {}
8+
_ => {} // ok
89
}
910

10-
match 0.0 { //~ ERROR non-exhaustive patterns
11-
0.0..=1.0 => {}
11+
match 0.0 {
12+
//~^ ERROR non-exhaustive patterns
13+
0.0..=1.0 => {}
1214
}
1315

1416
match 1.0f64 {
15-
0.01f64 ..= 6.5f64 => {}
16-
0.02f64 => {} //~ ERROR unreachable pattern
17-
_ => {}
17+
0.01f64..=6.5f64 => {}
18+
0.005f64 => {}
19+
0.01f64 => {} //~ ERROR unreachable pattern
20+
0.02f64 => {} //~ ERROR unreachable pattern
21+
6.5f64 => {} //~ ERROR unreachable pattern
22+
6.6f64 => {}
23+
1.0f64..=4.0f64 => {} //~ ERROR unreachable pattern
24+
5.0f64..=7.0f64 => {}
25+
_ => {}
26+
};
27+
match 1.0f64 {
28+
0.01f64..6.5f64 => {}
29+
6.5f64 => {} // this is reachable
30+
_ => {}
31+
};
32+
33+
match 1.0f32 {
34+
0.01f32..=6.5f32 => {}
35+
0.01f32 => {} //~ ERROR unreachable pattern
36+
0.02f32 => {} //~ ERROR unreachable pattern
37+
6.5f32 => {} //~ ERROR unreachable pattern
38+
_ => {}
39+
};
40+
match 1.0f32 {
41+
0.01f32..6.5f32 => {}
42+
6.5f32 => {} // this is reachable
43+
_ => {}
1844
};
1945
}
+44-8
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,64 @@
11
error[E0004]: non-exhaustive patterns: `_` not covered
2-
--> $DIR/floats.rs:10:11
2+
--> $DIR/floats.rs:11:11
33
|
44
LL | match 0.0 {
55
| ^^^ pattern `_` not covered
66
|
77
= note: the matched value is of type `f64`
88
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
99
|
10-
LL ~ 0.0..=1.0 => {},
11-
LL + _ => todo!()
10+
LL ~ 0.0..=1.0 => {},
11+
LL + _ => todo!()
1212
|
1313

1414
error: unreachable pattern
15-
--> $DIR/floats.rs:16:7
15+
--> $DIR/floats.rs:19:9
1616
|
17-
LL | 0.02f64 => {}
18-
| ^^^^^^^
17+
LL | 0.01f64 => {}
18+
| ^^^^^^^
1919
|
2020
note: the lint level is defined here
21-
--> $DIR/floats.rs:2:9
21+
--> $DIR/floats.rs:3:9
2222
|
2323
LL | #![deny(unreachable_patterns)]
2424
| ^^^^^^^^^^^^^^^^^^^^
2525

26-
error: aborting due to 2 previous errors
26+
error: unreachable pattern
27+
--> $DIR/floats.rs:20:9
28+
|
29+
LL | 0.02f64 => {}
30+
| ^^^^^^^
31+
32+
error: unreachable pattern
33+
--> $DIR/floats.rs:21:9
34+
|
35+
LL | 6.5f64 => {}
36+
| ^^^^^^
37+
38+
error: unreachable pattern
39+
--> $DIR/floats.rs:23:9
40+
|
41+
LL | 1.0f64..=4.0f64 => {}
42+
| ^^^^^^^^^^^^^^^
43+
44+
error: unreachable pattern
45+
--> $DIR/floats.rs:35:9
46+
|
47+
LL | 0.01f32 => {}
48+
| ^^^^^^^
49+
50+
error: unreachable pattern
51+
--> $DIR/floats.rs:36:9
52+
|
53+
LL | 0.02f32 => {}
54+
| ^^^^^^^
55+
56+
error: unreachable pattern
57+
--> $DIR/floats.rs:37:9
58+
|
59+
LL | 6.5f32 => {}
60+
| ^^^^^^
61+
62+
error: aborting due to 8 previous errors
2763

2864
For more information about this error, try `rustc --explain E0004`.

0 commit comments

Comments
 (0)