diff options
| author | Ralf Jung <post@ralfj.de> | 2025-07-28 16:59:06 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2025-08-14 09:39:39 +0200 |
| commit | 3f1e99dca47b2cfc33906f1f1334fbed3a9fc4ce (patch) | |
| tree | 4041bd26584370d48d0b7b4150e81f07807c1762 | |
| parent | 2c1ac85679678dfe5cce7ea8037735b0349ceaf3 (diff) | |
| download | rust-3f1e99dca47b2cfc33906f1f1334fbed3a9fc4ce.tar.gz rust-3f1e99dca47b2cfc33906f1f1334fbed3a9fc4ce.zip | |
PatKind: store constants as valtrees
| -rw-r--r-- | compiler/rustc_middle/src/thir.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/thir/visit.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/builder/matches/match_pair.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/builder/matches/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/mod.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_mir_build/src/thir/print.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_pattern_analysis/src/rustc.rs | 84 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/consts.rs | 2 | ||||
| -rw-r--r-- | tests/ui/thir-print/thir-tree-loop-match.stdout | 4 |
11 files changed, 68 insertions, 78 deletions
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3dd6d2c8928..8569f57b79d 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -832,17 +832,20 @@ pub enum PatKind<'tcx> { }, /// One of the following: - /// * `&str` (represented as a valtree), which will be handled as a string pattern and thus + /// * `&str`, which will be handled as a string pattern and thus /// exhaustiveness checking will detect if you use the same string twice in different /// patterns. - /// * integer, bool, char or float (represented as a valtree), which will be handled by + /// * integer, bool, char or float, which will be handled by /// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are /// much simpler. /// * raw pointers derived from integers, other raw pointers will have already resulted in an // error. /// * `String`, if `string_deref_patterns` is enabled. Constant { - value: mir::Const<'tcx>, + // Not using `ty::Value` since this is conceptually not a type-level constant. In + // particular, it can have raw pointers. + ty: Ty<'tcx>, + value: ty::ValTree<'tcx>, }, /// Pattern obtained by converting a constant (inline or named) to its pattern diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index dcfa6c4db32..9d3ba74ad0f 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -265,7 +265,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>( PatKind::Missing | PatKind::Wild | PatKind::Binding { subpattern: None, .. } - | PatKind::Constant { value: _ } + | PatKind::Constant { .. } | PatKind::Range(_) | PatKind::Never | PatKind::Error(_) => {} diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 9825b947fe0..dbe4ab9937f 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -146,9 +146,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { for arm in rest { let arm = &self.thir[*arm]; let value = match arm.pattern.kind { - PatKind::Constant { value } => value, + PatKind::Constant { value, .. } => value, PatKind::ExpandedConstant { ref subpattern, def_id: _ } - if let PatKind::Constant { value } = subpattern.kind => + if let PatKind::Constant { value, .. } = subpattern.kind => { value } @@ -160,7 +160,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { }); } }; - values.push(value.eval_bits(self.tcx, self.typing_env)); + values.push(value.unwrap_leaf().to_bits_unchecked()); targets.push(self.parse_block(arm.body)?); } diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 7a848536d0e..19ea9cd52b2 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -146,7 +146,11 @@ impl<'tcx> MatchPairTree<'tcx> { } } - PatKind::Constant { value } => Some(TestCase::Constant { value }), + PatKind::Constant { ty: value_ty, value } => { + // FIXME: `TestCase::Constant` should probably represent that it is always a `ValTree`. + let value = Const::Ty(value_ty, ty::Const::new_value(cx.tcx, value, value_ty)); + Some(TestCase::Constant { value }) + } PatKind::AscribeUserType { ascription: Ascription { ref annotation, variance }, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 94ae5dadd8a..b347d2dbd2a 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1321,7 +1321,7 @@ enum TestKind<'tcx> { value: Const<'tcx>, // Integer types are handled by `SwitchInt`, and constants with ADT // types and `&[T]` types are converted back into patterns, so this can - // only be `&str`, `f32` or `f64`. + // only be `&str` or `f*`. ty: Ty<'tcx>, }, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index a501cdf88c2..c1e9da3925e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -11,11 +11,11 @@ use rustc_index::Idx; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::span_bug; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitableExt, TypeVisitor, ValTree, }; -use rustc_middle::{mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::traits::ObligationCause; @@ -288,16 +288,12 @@ impl<'tcx> ConstToPat<'tcx> { // when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`. // This works because `str` and `&str` have the same valtree representation. let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty); - PatKind::Constant { - value: mir::Const::Ty(ref_str_ty, ty::Const::new_value(tcx, cv, ref_str_ty)), - } + PatKind::Constant { ty: ref_str_ty, value: cv } } ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. - ty::Str => PatKind::Constant { - value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), - }, + ty::Str => PatKind::Constant { ty, value: cv }, // All other references are converted into deref patterns and then recursively // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. @@ -326,15 +322,13 @@ impl<'tcx> ConstToPat<'tcx> { // Also see <https://github.com/rust-lang/rfcs/pull/3535>. return self.mk_err(tcx.dcx().create_err(NaNPattern { span }), ty); } else { - PatKind::Constant { - value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), - } + PatKind::Constant { ty, value: cv } } } ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. - PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) } + PatKind::Constant { ty, value: cv } } ty::FnPtr(..) => { unreachable!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a44afed5492..25fff0a3c23 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::thir::{ use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode}; -use rustc_middle::{bug, span_bug}; +use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; use rustc_span::{ErrorGuaranteed, Span}; use tracing::{debug, instrument}; @@ -156,12 +156,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } // The unpeeled kind should now be a constant, giving us the endpoint value. - let PatKind::Constant { value } = kind else { + let PatKind::Constant { ty, value } = kind else { let msg = format!("found bad range pattern endpoint `{expr:?}` outside of error recovery"); return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); }; - + // FIXME: `Finite` should probably take a `ValTree` or even a `ScalarInt` + // (but it should also be the same type as what `TestCase::Constant` uses, or at least + // easy to convert). + let value = mir::Const::Ty(ty, ty::Const::new_value(self.tcx, value, ty)); Ok(Some(PatRangeBoundary::Finite(value))) } @@ -244,7 +247,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { (RangeEnd::Included, Some(Ordering::Less)) => {} // `x..=y` where `x == y` and `x` and `y` are finite. (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => { - kind = PatKind::Constant { value: lo.as_finite().unwrap() }; + // FIXME: silly conversion because not all pattern stuff uses valtrees yet. + let mir::Const::Ty(ty, val) = lo.as_finite().unwrap() else { unreachable!() }; + kind = PatKind::Constant { ty, value: val.to_value().valtree }; } // `..=x` where `x == ty::MIN`. (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {} diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 5efc4be2de2..899f3e04ba2 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -761,7 +761,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Constant { value } => { + PatKind::Constant { value, ty: _ } => { print_indented!(self, "Constant {", depth_lvl + 1); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 0c1b0d622f2..0396cdc1aa2 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -517,78 +517,57 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ), } } - PatKind::Constant { value } => { + PatKind::Constant { ty: value_ty, value } => { match ty.kind() { ty::Bool => { - ctor = match value.try_eval_bool(cx.tcx, cx.typing_env) { - Some(b) => Bool(b), - None => Opaque(OpaqueId::new()), - }; + ctor = Bool(value.unwrap_leaf().try_to_bool().unwrap()); fields = vec![]; arity = 0; } ty::Char | ty::Int(_) | ty::Uint(_) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - let x = match *ty.kind() { - ty::Int(ity) => { - let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); - MaybeInfiniteInt::new_finite_int(bits, size) - } - _ => MaybeInfiniteInt::new_finite_uint(bits), - }; - IntRange(IntRange::from_singleton(x)) - } - None => Opaque(OpaqueId::new()), + ctor = { + let bits = value.unwrap_leaf().to_bits_unchecked(); + let x = match *ty.kind() { + ty::Int(ity) => { + let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); + MaybeInfiniteInt::new_finite_int(bits, size) + } + _ => MaybeInfiniteInt::new_finite_uint(bits), + }; + IntRange(IntRange::from_singleton(x)) }; fields = vec![]; arity = 0; } ty::Float(ty::FloatTy::F16) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - use rustc_apfloat::Float; - let value = rustc_apfloat::ieee::Half::from_bits(bits); - F16Range(value, value, RangeEnd::Included) - } - None => Opaque(OpaqueId::new()), - }; + use rustc_apfloat::Float; + let bits = value.unwrap_leaf().to_u16(); + let value = rustc_apfloat::ieee::Half::from_bits(bits.into()); + ctor = F16Range(value, value, RangeEnd::Included); fields = vec![]; arity = 0; } ty::Float(ty::FloatTy::F32) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - use rustc_apfloat::Float; - let value = rustc_apfloat::ieee::Single::from_bits(bits); - F32Range(value, value, RangeEnd::Included) - } - None => Opaque(OpaqueId::new()), - }; + use rustc_apfloat::Float; + let bits = value.unwrap_leaf().to_u32(); + let value = rustc_apfloat::ieee::Single::from_bits(bits.into()); + ctor = F32Range(value, value, RangeEnd::Included); fields = vec![]; arity = 0; } ty::Float(ty::FloatTy::F64) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - use rustc_apfloat::Float; - let value = rustc_apfloat::ieee::Double::from_bits(bits); - F64Range(value, value, RangeEnd::Included) - } - None => Opaque(OpaqueId::new()), - }; + use rustc_apfloat::Float; + let bits = value.unwrap_leaf().to_u64(); + let value = rustc_apfloat::ieee::Double::from_bits(bits.into()); + ctor = F64Range(value, value, RangeEnd::Included); fields = vec![]; arity = 0; } ty::Float(ty::FloatTy::F128) => { - ctor = match value.try_eval_bits(cx.tcx, cx.typing_env) { - Some(bits) => { - use rustc_apfloat::Float; - let value = rustc_apfloat::ieee::Quad::from_bits(bits); - F128Range(value, value, RangeEnd::Included) - } - None => Opaque(OpaqueId::new()), - }; + use rustc_apfloat::Float; + let bits = value.unwrap_leaf().to_u128(); + let value = rustc_apfloat::ieee::Quad::from_bits(bits); + ctor = F128Range(value, value, RangeEnd::Included); fields = vec![]; arity = 0; } @@ -601,7 +580,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // subfields. // Note: `t` is `str`, not `&str`. let ty = self.reveal_opaque_ty(*t); - let subpattern = DeconstructedPat::new(Str(*value), Vec::new(), 0, ty, pat); + // FIXME: why does `Str` need a `mir::Value`? + let val = mir::Const::Ty( + *value_ty, + ty::Const::new_value(self.tcx, *value, *value_ty), + ); + let subpattern = DeconstructedPat::new(Str(val), Vec::new(), 0, ty, pat); ctor = Ref; fields = vec![subpattern.at_index(0)]; arity = 1; diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index eb751da7c73..6d994a2b967 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -375,7 +375,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { } match pat.kind { - thir::PatKind::Constant { value } => value.has_non_region_param(), + thir::PatKind::Constant { value, .. } => value.has_non_region_param(), thir::PatKind::Range(ref range) => { let &thir::PatRange { lo, hi, .. } = range.as_ref(); lo.has_non_region_param() || hi.has_non_region_param() diff --git a/tests/ui/thir-print/thir-tree-loop-match.stdout b/tests/ui/thir-print/thir-tree-loop-match.stdout index 5c4c50cb156..b3d11050bdc 100644 --- a/tests/ui/thir-print/thir-tree-loop-match.stdout +++ b/tests/ui/thir-print/thir-tree-loop-match.stdout @@ -121,7 +121,7 @@ body: span: $DIR/thir-tree-loop-match.rs:12:17: 12:21 (#0) kind: PatKind { Constant { - value: Ty(bool, true) + value: Leaf(0x01) } } } @@ -219,7 +219,7 @@ body: span: $DIR/thir-tree-loop-match.rs:16:17: 16:22 (#0) kind: PatKind { Constant { - value: Ty(bool, false) + value: Leaf(0x00) } } } |
