Skip to content

Commit 1870bd2

Browse files
committed
use ty::Value instead of manual pairs of types and valtrees
1 parent b39c019 commit 1870bd2

File tree

14 files changed

+84
-88
lines changed

14 files changed

+84
-88
lines changed

compiler/rustc_middle/src/mir/consts.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,11 @@ impl<'tcx> Const<'tcx> {
448448
Self::Val(val, ty)
449449
}
450450

451+
#[inline]
452+
pub fn from_ty_value(tcx: TyCtxt<'tcx>, val: ty::Value<'tcx>) -> Self {
453+
Self::Ty(val.ty, ty::Const::new_value(tcx, val.valtree, val.ty))
454+
}
455+
451456
pub fn from_bits(
452457
tcx: TyCtxt<'tcx>,
453458
bits: u128,

compiler/rustc_middle/src/thir.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -840,10 +840,7 @@ pub enum PatKind<'tcx> {
840840
/// much simpler.
841841
/// * `String`, if `string_deref_patterns` is enabled.
842842
Constant {
843-
// Not using `ty::Value` since this is conceptually not a type-level constant. In
844-
// particular, it can have raw pointers.
845-
ty: Ty<'tcx>,
846-
value: ty::ValTree<'tcx>,
843+
value: ty::Value<'tcx>,
847844
},
848845

849846
/// Pattern obtained by converting a constant (inline or named) to its pattern
@@ -935,17 +932,17 @@ impl<'tcx> PatRange<'tcx> {
935932
// Also, for performance, it's important to only do the second `try_to_bits` if necessary.
936933
let lo_is_min = match self.lo {
937934
PatRangeBoundary::NegInfinity => true,
938-
PatRangeBoundary::Finite(_ty, value) => {
939-
let lo = value.unwrap_leaf().to_bits(size) ^ bias;
935+
PatRangeBoundary::Finite(value) => {
936+
let lo = value.try_to_scalar_int().unwrap().to_bits(size) ^ bias;
940937
lo <= min
941938
}
942939
PatRangeBoundary::PosInfinity => false,
943940
};
944941
if lo_is_min {
945942
let hi_is_max = match self.hi {
946943
PatRangeBoundary::NegInfinity => false,
947-
PatRangeBoundary::Finite(_ty, value) => {
948-
let hi = value.unwrap_leaf().to_bits(size) ^ bias;
944+
PatRangeBoundary::Finite(value) => {
945+
let hi = value.try_to_scalar_int().unwrap().to_bits(size) ^ bias;
949946
hi > max || hi == max && self.end == RangeEnd::Included
950947
}
951948
PatRangeBoundary::PosInfinity => true,
@@ -958,10 +955,11 @@ impl<'tcx> PatRange<'tcx> {
958955
}
959956

960957
#[inline]
961-
pub fn contains(&self, value: ty::ValTree<'tcx>, tcx: TyCtxt<'tcx>) -> Option<bool> {
958+
pub fn contains(&self, value: ty::Value<'tcx>, tcx: TyCtxt<'tcx>) -> Option<bool> {
962959
use Ordering::*;
960+
debug_assert_eq!(self.ty, value.ty);
963961
let ty = self.ty;
964-
let value = PatRangeBoundary::Finite(ty, value);
962+
let value = PatRangeBoundary::Finite(value);
965963
// For performance, it's important to only do the second comparison if necessary.
966964
Some(
967965
match self.lo.compare_with(value, ty, tcx)? {
@@ -996,13 +994,10 @@ impl<'tcx> PatRange<'tcx> {
996994

997995
impl<'tcx> fmt::Display for PatRange<'tcx> {
998996
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
999-
if let &PatRangeBoundary::Finite(ty, value) = &self.lo {
1000-
// `ty::Value` has a reasonable pretty-printing implementation.
1001-
let value = ty::Value { ty, valtree: value };
997+
if let PatRangeBoundary::Finite(value) = &self.lo {
1002998
write!(f, "{value}")?;
1003999
}
1004-
if let &PatRangeBoundary::Finite(ty, value) = &self.hi {
1005-
let value = ty::Value { ty, valtree: value };
1000+
if let PatRangeBoundary::Finite(value) = &self.hi {
10061001
write!(f, "{}", self.end)?;
10071002
write!(f, "{value}")?;
10081003
} else {
@@ -1017,7 +1012,7 @@ impl<'tcx> fmt::Display for PatRange<'tcx> {
10171012
/// If present, the const must be of a numeric type.
10181013
#[derive(Copy, Clone, Debug, PartialEq, HashStable, TypeVisitable)]
10191014
pub enum PatRangeBoundary<'tcx> {
1020-
Finite(Ty<'tcx>, ty::ValTree<'tcx>),
1015+
Finite(ty::Value<'tcx>),
10211016
NegInfinity,
10221017
PosInfinity,
10231018
}
@@ -1028,15 +1023,15 @@ impl<'tcx> PatRangeBoundary<'tcx> {
10281023
matches!(self, Self::Finite(..))
10291024
}
10301025
#[inline]
1031-
pub fn as_finite(self) -> Option<ty::ValTree<'tcx>> {
1026+
pub fn as_finite(self) -> Option<ty::Value<'tcx>> {
10321027
match self {
1033-
Self::Finite(_ty, value) => Some(value),
1028+
Self::Finite(value) => Some(value),
10341029
Self::NegInfinity | Self::PosInfinity => None,
10351030
}
10361031
}
10371032
pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> u128 {
10381033
match self {
1039-
Self::Finite(_ty, value) => value.unwrap_leaf().to_bits_unchecked(),
1034+
Self::Finite(value) => value.try_to_scalar_int().unwrap().to_bits_unchecked(),
10401035
Self::NegInfinity => {
10411036
// Unwrap is ok because the type is known to be numeric.
10421037
ty.numeric_min_and_max_as_bits(tcx).unwrap().0
@@ -1063,9 +1058,7 @@ impl<'tcx> PatRangeBoundary<'tcx> {
10631058
// we can do scalar comparisons. E.g. `unicode-normalization` has
10641059
// many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared
10651060
// in this way.
1066-
(Finite(_, a), Finite(_, b))
1067-
if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) =>
1068-
{
1061+
(Finite(a), Finite(b)) if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) => {
10691062
if let (Some(a), Some(b)) = (a.try_to_scalar_int(), b.try_to_scalar_int()) {
10701063
let sz = ty.primitive_size(tcx);
10711064
let cmp = match ty.kind() {

compiler/rustc_middle/src/thir/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
265265
PatKind::Missing
266266
| PatKind::Wild
267267
| PatKind::Binding { subpattern: None, .. }
268-
| PatKind::Constant { .. }
268+
| PatKind::Constant { value: _ }
269269
| PatKind::Range(_)
270270
| PatKind::Never
271271
| PatKind::Error(_) => {}

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ pub type ConstToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, Er
135135
/// A type-level constant value.
136136
///
137137
/// Represents a typed, fully evaluated constant.
138+
/// Note that this is used by pattern elaboration to represent values which cannot occur in types,
139+
/// such as raw pointers and floats.
138140
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
139141
#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable, Lift)]
140142
pub struct Value<'tcx> {
@@ -149,15 +151,19 @@ impl<'tcx> Value<'tcx> {
149151
/// or an aggregate).
150152
#[inline]
151153
pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> {
152-
let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else {
153-
return None;
154-
};
155-
let scalar = self.valtree.try_to_scalar_int()?;
154+
let scalar = self.try_to_scalar_int()?;
156155
let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty);
157156
let size = tcx.layout_of(input).ok()?.size;
158157
Some(scalar.to_bits(size))
159158
}
160159

160+
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
161+
let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else {
162+
return None;
163+
};
164+
self.valtree.try_to_scalar_int()
165+
}
166+
161167
pub fn try_to_bool(self) -> Option<bool> {
162168
if !self.ty.is_bool() {
163169
return None;

compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
146146
for arm in rest {
147147
let arm = &self.thir[*arm];
148148
let value = match arm.pattern.kind {
149-
PatKind::Constant { value, .. } => value,
149+
PatKind::Constant { value } => value,
150150
PatKind::ExpandedConstant { ref subpattern, def_id: _ }
151-
if let PatKind::Constant { value, .. } = subpattern.kind =>
151+
if let PatKind::Constant { value } = subpattern.kind =>
152152
{
153153
value
154154
}
@@ -160,7 +160,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
160160
});
161161
}
162162
};
163-
values.push(value.unwrap_leaf().to_bits_unchecked());
163+
values.push(value.try_to_scalar_int().unwrap().to_bits_unchecked());
164164
targets.push(self.parse_block(arm.body)?);
165165
}
166166

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ impl<'tcx> MatchPairTree<'tcx> {
136136
}
137137
}
138138

139-
PatKind::Constant { ty, value } => Some(TestCase::Constant { ty, value }),
139+
PatKind::Constant { value } => Some(TestCase::Constant { value }),
140140

141141
PatKind::AscribeUserType {
142142
ascription: Ascription { ref annotation, variance },

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ struct Ascription<'tcx> {
12601260
#[derive(Debug, Clone)]
12611261
enum TestCase<'tcx> {
12621262
Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },
1263-
Constant { ty: Ty<'tcx>, value: ty::ValTree<'tcx> },
1263+
Constant { value: ty::Value<'tcx> },
12641264
Range(Arc<PatRange<'tcx>>),
12651265
Slice { len: usize, variable_length: bool },
12661266
Deref { temp: Place<'tcx>, mutability: Mutability },
@@ -1333,8 +1333,7 @@ enum TestKind<'tcx> {
13331333
/// Test for equality with value, possibly after an unsizing coercion to
13341334
/// `ty`,
13351335
Eq {
1336-
value: ty::ValTree<'tcx>,
1337-
value_ty: Ty<'tcx>,
1336+
value: ty::Value<'tcx>,
13381337
// Integer types are handled by `SwitchInt`, and constants with ADT
13391338
// types and `&[T]` types are converted back into patterns, so this can
13401339
// only be `&str` or `f*`.
@@ -1374,15 +1373,15 @@ enum TestBranch<'tcx> {
13741373
/// Success branch, used for tests with two possible outcomes.
13751374
Success,
13761375
/// Branch corresponding to this constant.
1377-
Constant(ty::ValTree<'tcx>, u128),
1376+
Constant(ty::Value<'tcx>, u128),
13781377
/// Branch corresponding to this variant.
13791378
Variant(VariantIdx),
13801379
/// Failure branch for tests with two possible outcomes, and "otherwise" branch for other tests.
13811380
Failure,
13821381
}
13831382

13841383
impl<'tcx> TestBranch<'tcx> {
1385-
fn as_constant(&self) -> Option<ty::ValTree<'tcx>> {
1384+
fn as_constant(&self) -> Option<ty::Value<'tcx>> {
13861385
if let Self::Constant(v, _) = self { Some(*v) } else { None }
13871386
}
13881387
}

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

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3535

3636
TestCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If,
3737
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => TestKind::SwitchInt,
38-
TestCase::Constant { value, ty: value_ty } => {
39-
TestKind::Eq { value, value_ty, cast_ty: match_pair.pattern_ty }
40-
}
38+
TestCase::Constant { value } => TestKind::Eq { value, cast_ty: match_pair.pattern_ty },
4139

4240
TestCase::Range(ref range) => {
4341
assert_eq!(range.ty, match_pair.pattern_ty);
@@ -137,14 +135,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
137135
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
138136
}
139137

140-
TestKind::Eq { value, value_ty, mut cast_ty } => {
138+
TestKind::Eq { value, mut cast_ty } => {
141139
let tcx = self.tcx;
142140
let success_block = target_block(TestBranch::Success);
143141
let fail_block = target_block(TestBranch::Failure);
144142

145-
let mut expect_ty = value_ty;
146-
let value = Const::Ty(value_ty, ty::Const::new_value(tcx, value, value_ty));
147-
let mut expect = self.literal_operand(test.span, value);
143+
let mut expect_ty = value.ty;
144+
let mut expect = self.literal_operand(test.span, Const::from_ty_value(tcx, value));
148145

149146
let mut place = place;
150147
let mut block = block;
@@ -201,7 +198,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
201198
cast_ty = ref_str_ty;
202199
}
203200
&ty::Pat(base, _) => {
204-
assert_eq!(cast_ty, value_ty);
201+
assert_eq!(cast_ty, value.ty);
205202
assert!(base.is_trivially_pure_clone_copy());
206203

207204
let transmuted_place = self.temp(base, test.span);
@@ -282,8 +279,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
282279
};
283280

284281
if let Some(lo) = range.lo.as_finite() {
285-
let lo = Const::Ty(range.ty, ty::Const::new_value(self.tcx, lo, range.ty));
286-
let lo = self.literal_operand(test.span, lo);
282+
let lo = self.literal_operand(test.span, Const::from_ty_value(self.tcx, lo));
287283
self.compare(
288284
block,
289285
intermediate_block,
@@ -296,8 +292,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
296292
};
297293

298294
if let Some(hi) = range.hi.as_finite() {
299-
let hi = Const::Ty(range.ty, ty::Const::new_value(self.tcx, hi, range.ty));
300-
let hi = self.literal_operand(test.span, hi);
295+
let hi = self.literal_operand(test.span, Const::from_ty_value(self.tcx, hi));
301296
let op = match range.end {
302297
RangeEnd::Included => BinOp::Le,
303298
RangeEnd::Excluded => BinOp::Lt,
@@ -553,7 +548,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
553548
//
554549
// FIXME(#29623) we could use PatKind::Range to rule
555550
// things out here, in some cases.
556-
(TestKind::SwitchInt, &TestCase::Constant { value, .. })
551+
(TestKind::SwitchInt, &TestCase::Constant { value })
557552
if is_switch_ty(match_pair.pattern_ty) =>
558553
{
559554
// An important invariant of candidate sorting is that a candidate
@@ -580,7 +575,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
580575
None
581576
} else {
582577
fully_matched = true;
583-
let bits = value.unwrap_leaf().to_bits_unchecked();
578+
let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked();
584579
Some(TestBranch::Constant(value, bits))
585580
}
586581
}
@@ -602,9 +597,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
602597
})
603598
}
604599

605-
(TestKind::If, TestCase::Constant { value, .. }) => {
600+
(TestKind::If, TestCase::Constant { value }) => {
606601
fully_matched = true;
607-
let value = value.unwrap_leaf().try_to_bool().unwrap_or_else(|_| {
602+
let value = value.try_to_bool().unwrap_or_else(|| {
608603
span_bug!(test.span, "expected boolean value but got {value:?}")
609604
});
610605
Some(if value { TestBranch::Success } else { TestBranch::Failure })
@@ -687,7 +682,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
687682
if !test.overlaps(pat, self.tcx)? { Some(TestBranch::Failure) } else { None }
688683
}
689684
}
690-
(TestKind::Range(range), &TestCase::Constant { value, .. }) => {
685+
(TestKind::Range(range), &TestCase::Constant { value }) => {
691686
fully_matched = false;
692687
if !range.contains(value, self.tcx)? {
693688
// `value` is not contained in the testing range,

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,12 @@ impl<'tcx> ConstToPat<'tcx> {
287287
// when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`.
288288
// This works because `str` and `&str` have the same valtree representation.
289289
let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty);
290-
PatKind::Constant { ty: ref_str_ty, value: cv }
290+
PatKind::Constant { value: ty::Value { ty: ref_str_ty, valtree: cv } }
291291
}
292292
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
293293
// `&str` is represented as a valtree, let's keep using this
294294
// optimization for now.
295-
ty::Str => PatKind::Constant { ty, value: cv },
295+
ty::Str => PatKind::Constant { value: ty::Value { ty, valtree: cv } },
296296
// All other references are converted into deref patterns and then recursively
297297
// convert the dereferenced constant to a pattern that is the sub-pattern of the
298298
// deref pattern.
@@ -321,13 +321,13 @@ impl<'tcx> ConstToPat<'tcx> {
321321
// Also see <https://github.com/rust-lang/rfcs/pull/3535>.
322322
return self.mk_err(tcx.dcx().create_err(NaNPattern { span }), ty);
323323
} else {
324-
PatKind::Constant { ty, value: cv }
324+
PatKind::Constant { value: ty::Value { ty, valtree: cv } }
325325
}
326326
}
327327
ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
328328
// The raw pointers we see here have been "vetted" by valtree construction to be
329329
// just integers, so we simply allow them.
330-
PatKind::Constant { ty, value: cv }
330+
PatKind::Constant { value: ty::Value { ty, valtree: cv } }
331331
}
332332
ty::FnPtr(..) => {
333333
unreachable!(

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
156156
}
157157

158158
// The unpeeled kind should now be a constant, giving us the endpoint value.
159-
let PatKind::Constant { ty, value } = kind else {
159+
let PatKind::Constant { value } = kind else {
160160
let msg =
161161
format!("found bad range pattern endpoint `{expr:?}` outside of error recovery");
162162
return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
163163
};
164-
Ok(Some(PatRangeBoundary::Finite(ty, value)))
164+
Ok(Some(PatRangeBoundary::Finite(value)))
165165
}
166166

167167
/// Overflowing literals are linted against in a late pass. This is mostly fine, except when we
@@ -243,7 +243,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
243243
(RangeEnd::Included, Some(Ordering::Less)) => {}
244244
// `x..=y` where `x == y` and `x` and `y` are finite.
245245
(RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => {
246-
kind = PatKind::Constant { ty, value: lo.as_finite().unwrap() };
246+
kind = PatKind::Constant { value: lo.as_finite().unwrap() };
247247
}
248248
// `..=x` where `x == ty::MIN`.
249249
(RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {}

0 commit comments

Comments
 (0)