Skip to content

Commit 854e311

Browse files
committed
Encode int/float/bool/char patterns directly as ScalarInt
1 parent 96d8ae2 commit 854e311

25 files changed

+192
-132
lines changed

compiler/rustc_mir_build/src/build/matches/simplify.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
196196
Err(match_pair)
197197
}
198198

199-
PatKind::Range(PatRange { lo, hi, end }) => {
200-
let (range, bias) = match *lo.ty.kind() {
199+
PatKind::Range(PatRange { lo, hi, end, ty }) => {
200+
let (range, bias) = match *ty.kind() {
201201
ty::Char => {
202202
(Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
203203
}
@@ -215,18 +215,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
215215
_ => (None, 0),
216216
};
217217
if let Some((min, max, sz)) = range {
218-
if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
219-
// We want to compare ranges numerically, but the order of the bitwise
220-
// representation of signed integers does not match their numeric order.
221-
// Thus, to correct the ordering, we need to shift the range of signed
222-
// integers to correct the comparison. This is achieved by XORing with a
223-
// bias (see pattern/_match.rs for another pertinent example of this
224-
// pattern).
225-
let (lo, hi) = (lo ^ bias, hi ^ bias);
226-
if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
227-
// Irrefutable pattern match.
228-
return Ok(());
229-
}
218+
let lo = lo.assert_bits(sz);
219+
let hi = hi.assert_bits(sz);
220+
// We want to compare ranges numerically, but the order of the bitwise
221+
// representation of signed integers does not match their numeric order.
222+
// Thus, to correct the ordering, we need to shift the range of signed
223+
// integers to correct the comparison. This is achieved by XORing with a
224+
// bias (see pattern/_match.rs for another pertinent example of this
225+
// pattern).
226+
let (lo, hi) = (lo ^ bias, hi ^ bias);
227+
if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) {
228+
// Irrefutable pattern match.
229+
return Ok(());
230230
}
231231
}
232232
Err(match_pair)

compiler/rustc_mir_build/src/build/matches/test.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::thir::*;
1313
use rustc_data_structures::fx::FxIndexMap;
1414
use rustc_hir::{LangItem, RangeEnd};
1515
use rustc_index::bit_set::BitSet;
16+
use rustc_middle::mir::interpret::ConstValue;
1617
use rustc_middle::mir::*;
1718
use rustc_middle::ty::subst::{GenericArg, Subst};
1819
use rustc_middle::ty::util::IntTypeExt;
@@ -58,8 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5859
},
5960

6061
PatKind::Range(range) => {
61-
assert_eq!(range.lo.ty, match_pair.pattern.ty);
62-
assert_eq!(range.hi.ty, match_pair.pattern.ty);
62+
assert_eq!(range.ty, match_pair.pattern.ty);
6363
Test { span: match_pair.pattern.span, kind: TestKind::Range(range) }
6464
}
6565

@@ -271,11 +271,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
271271
}
272272
}
273273

274-
TestKind::Range(PatRange { ref lo, ref hi, ref end }) => {
274+
TestKind::Range(PatRange { lo, hi, ref end, ty }) => {
275275
let lower_bound_success = self.cfg.start_new_block();
276276
let target_blocks = make_target_blocks(self);
277277

278278
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
279+
let lo = ty::Const::from_value(self.tcx, ConstValue::Scalar(lo.into()), ty);
280+
let hi = ty::Const::from_value(self.tcx, ConstValue::Scalar(hi.into()), ty);
279281
let lo = self.literal_operand(test.span, lo);
280282
let hi = self.literal_operand(test.span, hi);
281283
let val = Operand::Copy(place);
@@ -640,9 +642,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
640642

641643
let tcx = self.tcx;
642644

643-
let test_ty = test.lo.ty;
644-
let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?;
645-
let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?;
645+
let test_ty = match_pair.pattern.ty;
646+
let test_lo =
647+
ty::Const::from_value(tcx, ConstValue::Scalar(test.lo.into()), test_ty);
648+
let test_hi =
649+
ty::Const::from_value(tcx, ConstValue::Scalar(test.hi.into()), test_ty);
650+
let pat_lo =
651+
ty::Const::from_value(tcx, ConstValue::Scalar(test.lo.into()), test_ty);
652+
let pat_hi =
653+
ty::Const::from_value(tcx, ConstValue::Scalar(test.hi.into()), test_ty);
654+
let lo = compare_const_vals(tcx, test_lo, pat_hi, self.param_env, test_ty)?;
655+
let hi = compare_const_vals(tcx, test_hi, pat_lo, self.param_env, test_ty)?;
646656

647657
match (test.end, pat.end, lo, hi) {
648658
// pat < test
@@ -769,8 +779,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
769779

770780
let tcx = self.tcx;
771781

772-
let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty)?;
773-
let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty)?;
782+
let lo = ty::Const::from_value(tcx, ConstValue::Scalar(range.lo.into()), value.ty);
783+
let hi = ty::Const::from_value(tcx, ConstValue::Scalar(range.hi.into()), value.ty);
784+
let a = compare_const_vals(tcx, lo, value, self.param_env, value.ty)?;
785+
let b = compare_const_vals(tcx, value, hi, self.param_env, value.ty)?;
774786

775787
match (b, range.end) {
776788
(Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true),

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

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ use rustc_index::vec::Idx;
5454

5555
use rustc_hir::def_id::DefId;
5656
use rustc_hir::{HirId, RangeEnd};
57+
use rustc_middle::mir::interpret::ConstValue;
5758
use rustc_middle::mir::Field;
5859
use rustc_middle::ty::layout::IntegerExt;
59-
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
60+
use rustc_middle::ty::{self, Const, ScalarInt, Ty, TyCtxt};
6061
use rustc_session::lint;
6162
use rustc_span::{Span, DUMMY_SP};
6263
use rustc_target::abi::{Integer, Size, VariantIdx};
@@ -203,14 +204,18 @@ impl IntRange {
203204
let bias = IntRange::signed_bias(tcx, ty);
204205
let (lo, hi) = (lo ^ bias, hi ^ bias);
205206

206-
let env = ty::ParamEnv::empty().and(ty);
207-
let lo_const = ty::Const::from_bits(tcx, lo, env);
208-
let hi_const = ty::Const::from_bits(tcx, hi, env);
209-
210207
let kind = if lo == hi {
211-
PatKind::Constant { value: lo_const }
208+
let ty = ty::ParamEnv::empty().and(ty);
209+
PatKind::Constant { value: ty::Const::from_bits(tcx, lo, ty) }
212210
} else {
213-
PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included })
211+
let param_env_and_ty = ty::ParamEnv::empty().and(ty);
212+
let size = tcx.layout_of(param_env_and_ty).unwrap().size;
213+
PatKind::Range(PatRange {
214+
lo: ScalarInt::from_uint(lo, size),
215+
hi: ScalarInt::from_uint(hi, size),
216+
end: RangeEnd::Included,
217+
ty,
218+
})
214219
};
215220

216221
Pat { ty, span: DUMMY_SP, kind: Box::new(kind) }
@@ -587,7 +592,7 @@ pub(super) enum Constructor<'tcx> {
587592
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
588593
IntRange(IntRange),
589594
/// Ranges of floating-point literal values (`2.0..=5.2`).
590-
FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
595+
FloatRange(ScalarInt, ScalarInt, RangeEnd),
591596
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
592597
Str(&'tcx ty::Const<'tcx>),
593598
/// Array and slice patterns.
@@ -650,7 +655,11 @@ impl<'tcx> Constructor<'tcx> {
650655
IntRange(int_range)
651656
} else {
652657
match pat.ty.kind() {
653-
ty::Float(_) => FloatRange(value, value, RangeEnd::Included),
658+
ty::Float(_) => {
659+
let value =
660+
value.val.eval(cx.tcx, cx.param_env).try_to_scalar_int().unwrap();
661+
FloatRange(value, value, RangeEnd::Included)
662+
}
654663
// In `expand_pattern`, we convert string literals to `&CONST` patterns with
655664
// `CONST` a pattern of type `str`. In truth this contains a constant of type
656665
// `&str`.
@@ -662,13 +671,13 @@ impl<'tcx> Constructor<'tcx> {
662671
}
663672
}
664673
}
665-
&PatKind::Range(PatRange { lo, hi, end }) => {
666-
let ty = lo.ty;
674+
&PatKind::Range(PatRange { lo, hi, end, ty }) => {
675+
let size = cx.tcx.layout_of(cx.param_env.and(ty)).unwrap().size;
667676
if let Some(int_range) = IntRange::from_range(
668677
cx.tcx,
669-
lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
670-
hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
671-
ty,
678+
lo.assert_bits(size),
679+
hi.assert_bits(size),
680+
pat.ty,
672681
&end,
673682
) {
674683
IntRange(int_range)
@@ -762,6 +771,26 @@ impl<'tcx> Constructor<'tcx> {
762771
FloatRange(self_from, self_to, self_end),
763772
FloatRange(other_from, other_to, other_end),
764773
) => {
774+
let self_to = ty::Const::from_value(
775+
pcx.cx.tcx,
776+
ConstValue::Scalar((*self_to).into()),
777+
pcx.ty,
778+
);
779+
let other_to = ty::Const::from_value(
780+
pcx.cx.tcx,
781+
ConstValue::Scalar((*other_to).into()),
782+
pcx.ty,
783+
);
784+
let self_from = ty::Const::from_value(
785+
pcx.cx.tcx,
786+
ConstValue::Scalar((*self_from).into()),
787+
pcx.ty,
788+
);
789+
let other_from = ty::Const::from_value(
790+
pcx.cx.tcx,
791+
ConstValue::Scalar((*other_from).into()),
792+
pcx.ty,
793+
);
765794
match (
766795
compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty),
767796
compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty),
@@ -1256,7 +1285,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12561285
}
12571286
},
12581287
&Str(value) => PatKind::Constant { value },
1259-
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }),
1288+
&FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end, ty: pcx.ty }),
12601289
IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty),
12611290
NonExhaustive => PatKind::Wild,
12621291
Wildcard => return Pat::wildcard_from_ty(pcx.ty),

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

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
2424
use rustc_middle::ty::{
2525
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
2626
};
27+
use rustc_middle::ty::{ConstInt, ScalarInt};
2728
use rustc_span::{Span, Symbol, DUMMY_SP};
2829
use rustc_target::abi::VariantIdx;
2930

@@ -196,8 +197,9 @@ pub enum PatKind<'tcx> {
196197

197198
#[derive(Copy, Clone, Debug, PartialEq)]
198199
pub struct PatRange<'tcx> {
199-
pub lo: &'tcx ty::Const<'tcx>,
200-
pub hi: &'tcx ty::Const<'tcx>,
200+
pub lo: ScalarInt,
201+
pub hi: ScalarInt,
202+
pub ty: Ty<'tcx>,
201203
pub end: RangeEnd,
202204
}
203205

@@ -316,10 +318,12 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
316318
write!(f, "{}", subpattern)
317319
}
318320
PatKind::Constant { value } => write!(f, "{}", value),
319-
PatKind::Range(PatRange { lo, hi, end }) => {
320-
write!(f, "{}", lo)?;
321+
PatKind::Range(PatRange { lo, hi, end, ty }) => {
322+
let lo = ConstInt::new(lo, ty.is_signed(), ty.is_ptr_sized_integral());
323+
let hi = ConstInt::new(hi, ty.is_signed(), ty.is_ptr_sized_integral());
324+
write!(f, "{:?}", lo)?;
321325
write!(f, "{}", end)?;
322-
write!(f, "{}", hi)
326+
write!(f, "{:?}", hi)
323327
}
324328
PatKind::Slice { ref prefix, ref slice, ref suffix }
325329
| PatKind::Array { ref prefix, ref slice, ref suffix } => {
@@ -447,10 +451,23 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
447451
assert_eq!(lo.ty, ty);
448452
assert_eq!(hi.ty, ty);
449453
let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
454+
let lo_const = lo;
455+
let lo = lo
456+
.val
457+
.eval(self.tcx, self.param_env)
458+
.try_to_scalar_int()
459+
.expect("range patterns must be integral");
460+
let hi = hi
461+
.val
462+
.eval(self.tcx, self.param_env)
463+
.try_to_scalar_int()
464+
.expect("range patterns must be integral");
450465
match (end, cmp) {
451466
// `x..y` where `x < y`.
452467
// Non-empty because the range includes at least `x`.
453-
(RangeEnd::Excluded, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
468+
(RangeEnd::Excluded, Some(Ordering::Less)) => {
469+
PatKind::Range(PatRange { lo, hi, end, ty })
470+
}
454471
// `x..y` where `x >= y`. The range is empty => error.
455472
(RangeEnd::Excluded, _) => {
456473
struct_span_err!(
@@ -463,9 +480,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
463480
PatKind::Wild
464481
}
465482
// `x..=y` where `x == y`.
466-
(RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo },
483+
(RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo_const },
467484
// `x..=y` where `x < y`.
468-
(RangeEnd::Included, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }),
485+
(RangeEnd::Included, Some(Ordering::Less)) => {
486+
PatKind::Range(PatRange { lo, hi, end, ty })
487+
}
469488
// `x..=y` where `x > y` hence the range is empty => error.
470489
(RangeEnd::Included, _) => {
471490
let mut err = struct_span_err!(

src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,43 +28,43 @@ fn main() -> () {
2828
StorageLive(_3); // scope 2 at $DIR/match_test.rs:12:5: 17:6
2929
FakeRead(ForMatchedPlace, _1); // scope 2 at $DIR/match_test.rs:12:11: 12:12
3030
_6 = Le(const 0_i32, _1); // scope 2 at $DIR/match_test.rs:13:9: 13:14
31-
switchInt(move _6) -> [false: bb4, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
31+
switchInt(move _6) -> [false: bb3, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
3232
}
3333

3434
bb1: {
3535
_7 = Lt(_1, const 10_i32); // scope 2 at $DIR/match_test.rs:13:9: 13:14
36-
switchInt(move _7) -> [false: bb4, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
36+
switchInt(move _7) -> [false: bb3, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
3737
}
3838

3939
bb2: {
40-
falseEdge -> [real: bb9, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
40+
falseEdge -> [real: bb9, imaginary: bb5]; // scope 2 at $DIR/match_test.rs:13:9: 13:14
4141
}
4242

4343
bb3: {
44-
_3 = const 3_i32; // scope 2 at $DIR/match_test.rs:16:14: 16:15
45-
goto -> bb14; // scope 2 at $DIR/match_test.rs:12:5: 17:6
44+
_4 = Le(const 10_i32, _1); // scope 2 at $DIR/match_test.rs:14:9: 14:16
45+
switchInt(move _4) -> [false: bb6, otherwise: bb4]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
4646
}
4747

4848
bb4: {
49-
_4 = Le(const 10_i32, _1); // scope 2 at $DIR/match_test.rs:14:9: 14:16
50-
switchInt(move _4) -> [false: bb7, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
49+
_5 = Le(_1, const 20_i32); // scope 2 at $DIR/match_test.rs:14:9: 14:16
50+
switchInt(move _5) -> [false: bb6, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
5151
}
5252

5353
bb5: {
54-
_5 = Le(_1, const 20_i32); // scope 2 at $DIR/match_test.rs:14:9: 14:16
55-
switchInt(move _5) -> [false: bb7, otherwise: bb6]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
54+
falseEdge -> [real: bb12, imaginary: bb7]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
5655
}
5756

5857
bb6: {
59-
falseEdge -> [real: bb12, imaginary: bb8]; // scope 2 at $DIR/match_test.rs:14:9: 14:16
58+
switchInt(_1) -> [-1_i32: bb7, otherwise: bb8]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
6059
}
6160

6261
bb7: {
63-
switchInt(_1) -> [-1_i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
62+
falseEdge -> [real: bb13, imaginary: bb8]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
6463
}
6564

6665
bb8: {
67-
falseEdge -> [real: bb13, imaginary: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11
66+
_3 = const 3_i32; // scope 2 at $DIR/match_test.rs:16:14: 16:15
67+
goto -> bb14; // scope 2 at $DIR/match_test.rs:12:5: 17:6
6868
}
6969

7070
bb9: {
@@ -83,7 +83,7 @@ fn main() -> () {
8383

8484
bb11: {
8585
StorageDead(_9); // scope 2 at $DIR/match_test.rs:13:23: 13:24
86-
falseEdge -> [real: bb3, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:13:18: 13:19
86+
falseEdge -> [real: bb3, imaginary: bb5]; // scope 2 at $DIR/match_test.rs:13:18: 13:19
8787
}
8888

8989
bb12: {

src/test/ui/consts/const-match-check.eval1.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
1+
error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered
22
--> $DIR/const-match-check.rs:25:15
33
|
44
LL | A = { let 0 = 0; 0 },
5-
| ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
5+
| ^ patterns `i32::MIN..=-1` and `1..=i32::MAX` not covered
66
|
77
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
88
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html

src/test/ui/consts/const-match-check.eval2.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
1+
error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered
22
--> $DIR/const-match-check.rs:31:24
33
|
44
LL | let x: [i32; { let 0 = 0; 0 }] = [];
5-
| ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
5+
| ^ patterns `i32::MIN..=-1` and `1..=i32::MAX` not covered
66
|
77
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
88
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html

0 commit comments

Comments
 (0)