about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-07-28 16:59:06 +0200
committerRalf Jung <post@ralfj.de>2025-08-14 09:39:39 +0200
commit3f1e99dca47b2cfc33906f1f1334fbed3a9fc4ce (patch)
tree4041bd26584370d48d0b7b4150e81f07807c1762
parent2c1ac85679678dfe5cce7ea8037735b0349ceaf3 (diff)
downloadrust-3f1e99dca47b2cfc33906f1f1334fbed3a9fc4ce.tar.gz
rust-3f1e99dca47b2cfc33906f1f1334fbed3a9fc4ce.zip
PatKind: store constants as valtrees
-rw-r--r--compiler/rustc_middle/src/thir.rs9
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs2
-rw-r--r--compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs6
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/match_pair.rs6
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs16
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs13
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs84
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs2
-rw-r--r--tests/ui/thir-print/thir-tree-loop-match.stdout4
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)
                                                                                                             }
                                                                                                         }
                                                                                                     }