Skip to content

Commit d61fdbf

Browse files
committed
pattern testing: store constants as valtrees
1 parent 3f1e99d commit d61fdbf

File tree

10 files changed

+106
-120
lines changed

10 files changed

+106
-120
lines changed

compiler/rustc_middle/src/thir.rs

Lines changed: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -937,17 +937,17 @@ impl<'tcx> PatRange<'tcx> {
937937
// Also, for performance, it's important to only do the second `try_to_bits` if necessary.
938938
let lo_is_min = match self.lo {
939939
PatRangeBoundary::NegInfinity => true,
940-
PatRangeBoundary::Finite(value) => {
941-
let lo = value.try_to_bits(size).unwrap() ^ bias;
940+
PatRangeBoundary::Finite(_ty, value) => {
941+
let lo = value.unwrap_leaf().to_bits(size) ^ bias;
942942
lo <= min
943943
}
944944
PatRangeBoundary::PosInfinity => false,
945945
};
946946
if lo_is_min {
947947
let hi_is_max = match self.hi {
948948
PatRangeBoundary::NegInfinity => false,
949-
PatRangeBoundary::Finite(value) => {
950-
let hi = value.try_to_bits(size).unwrap() ^ bias;
949+
PatRangeBoundary::Finite(_ty, value) => {
950+
let hi = value.unwrap_leaf().to_bits(size) ^ bias;
951951
hi > max || hi == max && self.end == RangeEnd::Included
952952
}
953953
PatRangeBoundary::PosInfinity => true,
@@ -960,22 +960,16 @@ impl<'tcx> PatRange<'tcx> {
960960
}
961961

962962
#[inline]
963-
pub fn contains(
964-
&self,
965-
value: mir::Const<'tcx>,
966-
tcx: TyCtxt<'tcx>,
967-
typing_env: ty::TypingEnv<'tcx>,
968-
) -> Option<bool> {
963+
pub fn contains(&self, value: ty::ValTree<'tcx>, tcx: TyCtxt<'tcx>) -> Option<bool> {
969964
use Ordering::*;
970-
debug_assert_eq!(self.ty, value.ty());
971965
let ty = self.ty;
972-
let value = PatRangeBoundary::Finite(value);
966+
let value = PatRangeBoundary::Finite(ty, value);
973967
// For performance, it's important to only do the second comparison if necessary.
974968
Some(
975-
match self.lo.compare_with(value, ty, tcx, typing_env)? {
969+
match self.lo.compare_with(value, ty, tcx)? {
976970
Less | Equal => true,
977971
Greater => false,
978-
} && match value.compare_with(self.hi, ty, tcx, typing_env)? {
972+
} && match value.compare_with(self.hi, ty, tcx)? {
979973
Less => true,
980974
Equal => self.end == RangeEnd::Included,
981975
Greater => false,
@@ -984,21 +978,16 @@ impl<'tcx> PatRange<'tcx> {
984978
}
985979

986980
#[inline]
987-
pub fn overlaps(
988-
&self,
989-
other: &Self,
990-
tcx: TyCtxt<'tcx>,
991-
typing_env: ty::TypingEnv<'tcx>,
992-
) -> Option<bool> {
981+
pub fn overlaps(&self, other: &Self, tcx: TyCtxt<'tcx>) -> Option<bool> {
993982
use Ordering::*;
994983
debug_assert_eq!(self.ty, other.ty);
995984
// For performance, it's important to only do the second comparison if necessary.
996985
Some(
997-
match other.lo.compare_with(self.hi, self.ty, tcx, typing_env)? {
986+
match other.lo.compare_with(self.hi, self.ty, tcx)? {
998987
Less => true,
999988
Equal => self.end == RangeEnd::Included,
1000989
Greater => false,
1001-
} && match self.lo.compare_with(other.hi, self.ty, tcx, typing_env)? {
990+
} && match self.lo.compare_with(other.hi, self.ty, tcx)? {
1002991
Less => true,
1003992
Equal => other.end == RangeEnd::Included,
1004993
Greater => false,
@@ -1009,10 +998,13 @@ impl<'tcx> PatRange<'tcx> {
1009998

1010999
impl<'tcx> fmt::Display for PatRange<'tcx> {
10111000
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1012-
if let PatRangeBoundary::Finite(value) = &self.lo {
1001+
if let &PatRangeBoundary::Finite(ty, value) = &self.lo {
1002+
// `ty::Value` has a reasonable pretty-printing implementation.
1003+
let value = ty::Value { ty, valtree: value };
10131004
write!(f, "{value}")?;
10141005
}
1015-
if let PatRangeBoundary::Finite(value) = &self.hi {
1006+
if let &PatRangeBoundary::Finite(ty, value) = &self.hi {
1007+
let value = ty::Value { ty, valtree: value };
10161008
write!(f, "{}", self.end)?;
10171009
write!(f, "{value}")?;
10181010
} else {
@@ -1027,7 +1019,7 @@ impl<'tcx> fmt::Display for PatRange<'tcx> {
10271019
/// If present, the const must be of a numeric type.
10281020
#[derive(Copy, Clone, Debug, PartialEq, HashStable, TypeVisitable)]
10291021
pub enum PatRangeBoundary<'tcx> {
1030-
Finite(mir::Const<'tcx>),
1022+
Finite(Ty<'tcx>, ty::ValTree<'tcx>),
10311023
NegInfinity,
10321024
PosInfinity,
10331025
}
@@ -1038,20 +1030,15 @@ impl<'tcx> PatRangeBoundary<'tcx> {
10381030
matches!(self, Self::Finite(..))
10391031
}
10401032
#[inline]
1041-
pub fn as_finite(self) -> Option<mir::Const<'tcx>> {
1033+
pub fn as_finite(self) -> Option<ty::ValTree<'tcx>> {
10421034
match self {
1043-
Self::Finite(value) => Some(value),
1035+
Self::Finite(_ty, value) => Some(value),
10441036
Self::NegInfinity | Self::PosInfinity => None,
10451037
}
10461038
}
1047-
pub fn eval_bits(
1048-
self,
1049-
ty: Ty<'tcx>,
1050-
tcx: TyCtxt<'tcx>,
1051-
typing_env: ty::TypingEnv<'tcx>,
1052-
) -> u128 {
1039+
pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> u128 {
10531040
match self {
1054-
Self::Finite(value) => value.eval_bits(tcx, typing_env),
1041+
Self::Finite(_ty, value) => value.unwrap_leaf().to_bits_unchecked(),
10551042
Self::NegInfinity => {
10561043
// Unwrap is ok because the type is known to be numeric.
10571044
ty.numeric_min_and_max_as_bits(tcx).unwrap().0
@@ -1063,14 +1050,8 @@ impl<'tcx> PatRangeBoundary<'tcx> {
10631050
}
10641051
}
10651052

1066-
#[instrument(skip(tcx, typing_env), level = "debug", ret)]
1067-
pub fn compare_with(
1068-
self,
1069-
other: Self,
1070-
ty: Ty<'tcx>,
1071-
tcx: TyCtxt<'tcx>,
1072-
typing_env: ty::TypingEnv<'tcx>,
1073-
) -> Option<Ordering> {
1053+
#[instrument(skip(tcx), level = "debug", ret)]
1054+
pub fn compare_with(self, other: Self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Ordering> {
10741055
use PatRangeBoundary::*;
10751056
match (self, other) {
10761057
// When comparing with infinities, we must remember that `0u8..` and `0u8..=255`
@@ -1084,7 +1065,9 @@ impl<'tcx> PatRangeBoundary<'tcx> {
10841065
// we can do scalar comparisons. E.g. `unicode-normalization` has
10851066
// many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared
10861067
// in this way.
1087-
(Finite(a), Finite(b)) if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) => {
1068+
(Finite(_, a), Finite(_, b))
1069+
if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) =>
1070+
{
10881071
if let (Some(a), Some(b)) = (a.try_to_scalar_int(), b.try_to_scalar_int()) {
10891072
let sz = ty.primitive_size(tcx);
10901073
let cmp = match ty.kind() {
@@ -1098,8 +1081,8 @@ impl<'tcx> PatRangeBoundary<'tcx> {
10981081
_ => {}
10991082
}
11001083

1101-
let a = self.eval_bits(ty, tcx, typing_env);
1102-
let b = other.eval_bits(ty, tcx, typing_env);
1084+
let a = self.eval_bits(ty, tcx);
1085+
let b = other.eval_bits(ty, tcx);
11031086

11041087
match ty.kind() {
11051088
ty::Float(ty::FloatTy::F16) => {

compiler/rustc_middle/src/ty/consts/valtree.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ use std::fmt;
22
use std::ops::Deref;
33

44
use rustc_data_structures::intern::Interned;
5+
use rustc_hir::def::Namespace;
56
use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
67

78
use super::ScalarInt;
89
use crate::mir::interpret::{ErrorHandled, Scalar};
10+
use crate::ty::print::{FmtPrinter, PrettyPrinter};
911
use crate::ty::{self, Ty, TyCtxt};
1012

1113
/// This datastructure is used to represent the value of constants used in the type system.
@@ -203,3 +205,14 @@ impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
203205
self.valtree
204206
}
205207
}
208+
209+
impl<'tcx> fmt::Display for Value<'tcx> {
210+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211+
ty::tls::with(move |tcx| {
212+
let cv = tcx.lift(*self).unwrap();
213+
let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
214+
p.pretty_print_const_valtree(cv, /*print_ty*/ true)?;
215+
f.write_str(&p.into_buffer())
216+
})
217+
}
218+
}

compiler/rustc_middle/src/ty/structural_impls.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use rustc_hir::def_id::LocalDefId;
1212
use rustc_span::source_map::Spanned;
1313
use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit};
1414

15-
use super::print::PrettyPrinter;
1615
use super::{GenericArg, GenericArgKind, Pattern, Region};
1716
use crate::mir::PlaceElem;
1817
use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths};
@@ -168,15 +167,11 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> {
168167
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169168
// If this is a value, we spend some effort to make it look nice.
170169
if let ConstKind::Value(cv) = self.kind() {
171-
return ty::tls::with(move |tcx| {
172-
let cv = tcx.lift(cv).unwrap();
173-
let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
174-
p.pretty_print_const_valtree(cv, /*print_ty*/ true)?;
175-
f.write_str(&p.into_buffer())
176-
});
170+
write!(f, "{}", cv)
171+
} else {
172+
// Fall back to something verbose.
173+
write!(f, "{:?}", self.kind())
177174
}
178-
// Fall back to something verbose.
179-
write!(f, "{:?}", self.kind())
180175
}
181176
}
182177

compiler/rustc_mir_build/src/builder/matches/match_pair.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,7 @@ impl<'tcx> MatchPairTree<'tcx> {
146146
}
147147
}
148148

149-
PatKind::Constant { ty: value_ty, value } => {
150-
// FIXME: `TestCase::Constant` should probably represent that it is always a `ValTree`.
151-
let value = Const::Ty(value_ty, ty::Const::new_value(cx.tcx, value, value_ty));
152-
Some(TestCase::Constant { value })
153-
}
149+
PatKind::Constant { ty, value } => Some(TestCase::Constant { ty, value }),
154150

155151
PatKind::AscribeUserType {
156152
ascription: Ascription { ref annotation, variance },

compiler/rustc_mir_build/src/builder/matches/mod.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
1616
use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node};
1717
use rustc_middle::bug;
1818
use rustc_middle::middle::region;
19-
use rustc_middle::mir::{self, *};
19+
use rustc_middle::mir::*;
2020
use rustc_middle::thir::{self, *};
2121
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind};
2222
use rustc_pattern_analysis::constructor::RangeEnd;
@@ -1245,7 +1245,7 @@ struct Ascription<'tcx> {
12451245
#[derive(Debug, Clone)]
12461246
enum TestCase<'tcx> {
12471247
Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
1248-
Constant { value: mir::Const<'tcx> },
1248+
Constant { ty: Ty<'tcx>, value: ty::ValTree<'tcx> },
12491249
Range(Arc<PatRange<'tcx>>),
12501250
Slice { len: usize, variable_length: bool },
12511251
Deref { temp: Place<'tcx>, mutability: Mutability },
@@ -1318,11 +1318,12 @@ enum TestKind<'tcx> {
13181318
/// Test for equality with value, possibly after an unsizing coercion to
13191319
/// `ty`,
13201320
Eq {
1321-
value: Const<'tcx>,
1321+
value: ty::ValTree<'tcx>,
1322+
value_ty: Ty<'tcx>,
13221323
// Integer types are handled by `SwitchInt`, and constants with ADT
13231324
// types and `&[T]` types are converted back into patterns, so this can
13241325
// only be `&str` or `f*`.
1325-
ty: Ty<'tcx>,
1326+
cast_ty: Ty<'tcx>,
13261327
},
13271328

13281329
/// Test whether the value falls within an inclusive or exclusive range.
@@ -1358,16 +1359,16 @@ enum TestBranch<'tcx> {
13581359
/// Success branch, used for tests with two possible outcomes.
13591360
Success,
13601361
/// Branch corresponding to this constant.
1361-
Constant(Const<'tcx>, u128),
1362+
Constant(ty::ValTree<'tcx>, u128),
13621363
/// Branch corresponding to this variant.
13631364
Variant(VariantIdx),
13641365
/// Failure branch for tests with two possible outcomes, and "otherwise" branch for other tests.
13651366
Failure,
13661367
}
13671368

13681369
impl<'tcx> TestBranch<'tcx> {
1369-
fn as_constant(&self) -> Option<&Const<'tcx>> {
1370-
if let Self::Constant(v, _) = self { Some(v) } else { None }
1370+
fn as_constant(&self) -> Option<ty::ValTree<'tcx>> {
1371+
if let Self::Constant(v, _) = self { Some(*v) } else { None }
13711372
}
13721373
}
13731374

0 commit comments

Comments
 (0)