about summary refs log tree commit diff
path: root/compiler/rustc_middle
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-07-28 18:16:47 +0200
committerRalf Jung <post@ralfj.de>2025-08-14 09:44:19 +0200
commitd61fdbf266cf25ddf8c4798fd86e21577c8664e8 (patch)
treee9baa4a40781eb0f2a2a54a9e62fb102434ac7aa /compiler/rustc_middle
parent3f1e99dca47b2cfc33906f1f1334fbed3a9fc4ce (diff)
downloadrust-d61fdbf266cf25ddf8c4798fd86e21577c8664e8.tar.gz
rust-d61fdbf266cf25ddf8c4798fd86e21577c8664e8.zip
pattern testing: store constants as valtrees
Diffstat (limited to 'compiler/rustc_middle')
-rw-r--r--compiler/rustc_middle/src/thir.rs73
-rw-r--r--compiler/rustc_middle/src/ty/consts/valtree.rs13
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs13
3 files changed, 45 insertions, 54 deletions
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 8569f57b79d..62f76671b78 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -937,8 +937,8 @@ impl<'tcx> PatRange<'tcx> {
         // Also, for performance, it's important to only do the second `try_to_bits` if necessary.
         let lo_is_min = match self.lo {
             PatRangeBoundary::NegInfinity => true,
-            PatRangeBoundary::Finite(value) => {
-                let lo = value.try_to_bits(size).unwrap() ^ bias;
+            PatRangeBoundary::Finite(_ty, value) => {
+                let lo = value.unwrap_leaf().to_bits(size) ^ bias;
                 lo <= min
             }
             PatRangeBoundary::PosInfinity => false,
@@ -946,8 +946,8 @@ impl<'tcx> PatRange<'tcx> {
         if lo_is_min {
             let hi_is_max = match self.hi {
                 PatRangeBoundary::NegInfinity => false,
-                PatRangeBoundary::Finite(value) => {
-                    let hi = value.try_to_bits(size).unwrap() ^ bias;
+                PatRangeBoundary::Finite(_ty, value) => {
+                    let hi = value.unwrap_leaf().to_bits(size) ^ bias;
                     hi > max || hi == max && self.end == RangeEnd::Included
                 }
                 PatRangeBoundary::PosInfinity => true,
@@ -960,22 +960,16 @@ impl<'tcx> PatRange<'tcx> {
     }
 
     #[inline]
-    pub fn contains(
-        &self,
-        value: mir::Const<'tcx>,
-        tcx: TyCtxt<'tcx>,
-        typing_env: ty::TypingEnv<'tcx>,
-    ) -> Option<bool> {
+    pub fn contains(&self, value: ty::ValTree<'tcx>, tcx: TyCtxt<'tcx>) -> Option<bool> {
         use Ordering::*;
-        debug_assert_eq!(self.ty, value.ty());
         let ty = self.ty;
-        let value = PatRangeBoundary::Finite(value);
+        let value = PatRangeBoundary::Finite(ty, value);
         // For performance, it's important to only do the second comparison if necessary.
         Some(
-            match self.lo.compare_with(value, ty, tcx, typing_env)? {
+            match self.lo.compare_with(value, ty, tcx)? {
                 Less | Equal => true,
                 Greater => false,
-            } && match value.compare_with(self.hi, ty, tcx, typing_env)? {
+            } && match value.compare_with(self.hi, ty, tcx)? {
                 Less => true,
                 Equal => self.end == RangeEnd::Included,
                 Greater => false,
@@ -984,21 +978,16 @@ impl<'tcx> PatRange<'tcx> {
     }
 
     #[inline]
-    pub fn overlaps(
-        &self,
-        other: &Self,
-        tcx: TyCtxt<'tcx>,
-        typing_env: ty::TypingEnv<'tcx>,
-    ) -> Option<bool> {
+    pub fn overlaps(&self, other: &Self, tcx: TyCtxt<'tcx>) -> Option<bool> {
         use Ordering::*;
         debug_assert_eq!(self.ty, other.ty);
         // For performance, it's important to only do the second comparison if necessary.
         Some(
-            match other.lo.compare_with(self.hi, self.ty, tcx, typing_env)? {
+            match other.lo.compare_with(self.hi, self.ty, tcx)? {
                 Less => true,
                 Equal => self.end == RangeEnd::Included,
                 Greater => false,
-            } && match self.lo.compare_with(other.hi, self.ty, tcx, typing_env)? {
+            } && match self.lo.compare_with(other.hi, self.ty, tcx)? {
                 Less => true,
                 Equal => other.end == RangeEnd::Included,
                 Greater => false,
@@ -1009,10 +998,13 @@ impl<'tcx> PatRange<'tcx> {
 
 impl<'tcx> fmt::Display for PatRange<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let PatRangeBoundary::Finite(value) = &self.lo {
+        if let &PatRangeBoundary::Finite(ty, value) = &self.lo {
+            // `ty::Value` has a reasonable pretty-printing implementation.
+            let value = ty::Value { ty, valtree: value };
             write!(f, "{value}")?;
         }
-        if let PatRangeBoundary::Finite(value) = &self.hi {
+        if let &PatRangeBoundary::Finite(ty, value) = &self.hi {
+            let value = ty::Value { ty, valtree: value };
             write!(f, "{}", self.end)?;
             write!(f, "{value}")?;
         } else {
@@ -1027,7 +1019,7 @@ impl<'tcx> fmt::Display for PatRange<'tcx> {
 /// If present, the const must be of a numeric type.
 #[derive(Copy, Clone, Debug, PartialEq, HashStable, TypeVisitable)]
 pub enum PatRangeBoundary<'tcx> {
-    Finite(mir::Const<'tcx>),
+    Finite(Ty<'tcx>, ty::ValTree<'tcx>),
     NegInfinity,
     PosInfinity,
 }
@@ -1038,20 +1030,15 @@ impl<'tcx> PatRangeBoundary<'tcx> {
         matches!(self, Self::Finite(..))
     }
     #[inline]
-    pub fn as_finite(self) -> Option<mir::Const<'tcx>> {
+    pub fn as_finite(self) -> Option<ty::ValTree<'tcx>> {
         match self {
-            Self::Finite(value) => Some(value),
+            Self::Finite(_ty, value) => Some(value),
             Self::NegInfinity | Self::PosInfinity => None,
         }
     }
-    pub fn eval_bits(
-        self,
-        ty: Ty<'tcx>,
-        tcx: TyCtxt<'tcx>,
-        typing_env: ty::TypingEnv<'tcx>,
-    ) -> u128 {
+    pub fn eval_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> u128 {
         match self {
-            Self::Finite(value) => value.eval_bits(tcx, typing_env),
+            Self::Finite(_ty, value) => value.unwrap_leaf().to_bits_unchecked(),
             Self::NegInfinity => {
                 // Unwrap is ok because the type is known to be numeric.
                 ty.numeric_min_and_max_as_bits(tcx).unwrap().0
@@ -1063,14 +1050,8 @@ impl<'tcx> PatRangeBoundary<'tcx> {
         }
     }
 
-    #[instrument(skip(tcx, typing_env), level = "debug", ret)]
-    pub fn compare_with(
-        self,
-        other: Self,
-        ty: Ty<'tcx>,
-        tcx: TyCtxt<'tcx>,
-        typing_env: ty::TypingEnv<'tcx>,
-    ) -> Option<Ordering> {
+    #[instrument(skip(tcx), level = "debug", ret)]
+    pub fn compare_with(self, other: Self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Ordering> {
         use PatRangeBoundary::*;
         match (self, other) {
             // When comparing with infinities, we must remember that `0u8..` and `0u8..=255`
@@ -1084,7 +1065,9 @@ impl<'tcx> PatRangeBoundary<'tcx> {
             // we can do scalar comparisons. E.g. `unicode-normalization` has
             // many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared
             // in this way.
-            (Finite(a), Finite(b)) if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) => {
+            (Finite(_, a), Finite(_, b))
+                if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) =>
+            {
                 if let (Some(a), Some(b)) = (a.try_to_scalar_int(), b.try_to_scalar_int()) {
                     let sz = ty.primitive_size(tcx);
                     let cmp = match ty.kind() {
@@ -1098,8 +1081,8 @@ impl<'tcx> PatRangeBoundary<'tcx> {
             _ => {}
         }
 
-        let a = self.eval_bits(ty, tcx, typing_env);
-        let b = other.eval_bits(ty, tcx, typing_env);
+        let a = self.eval_bits(ty, tcx);
+        let b = other.eval_bits(ty, tcx);
 
         match ty.kind() {
             ty::Float(ty::FloatTy::F16) => {
diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs
index d95006dcf4a..002a86a8897 100644
--- a/compiler/rustc_middle/src/ty/consts/valtree.rs
+++ b/compiler/rustc_middle/src/ty/consts/valtree.rs
@@ -2,10 +2,12 @@ use std::fmt;
 use std::ops::Deref;
 
 use rustc_data_structures::intern::Interned;
+use rustc_hir::def::Namespace;
 use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 
 use super::ScalarInt;
 use crate::mir::interpret::{ErrorHandled, Scalar};
+use crate::ty::print::{FmtPrinter, PrettyPrinter};
 use crate::ty::{self, Ty, TyCtxt};
 
 /// 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> {
         self.valtree
     }
 }
+
+impl<'tcx> fmt::Display for Value<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        ty::tls::with(move |tcx| {
+            let cv = tcx.lift(*self).unwrap();
+            let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
+            p.pretty_print_const_valtree(cv, /*print_ty*/ true)?;
+            f.write_str(&p.into_buffer())
+        })
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 0e2aff6f9bd..89ef46b1ae5 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -12,7 +12,6 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_span::source_map::Spanned;
 use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit};
 
-use super::print::PrettyPrinter;
 use super::{GenericArg, GenericArgKind, Pattern, Region};
 use crate::mir::PlaceElem;
 use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths};
@@ -168,15 +167,11 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // If this is a value, we spend some effort to make it look nice.
         if let ConstKind::Value(cv) = self.kind() {
-            return ty::tls::with(move |tcx| {
-                let cv = tcx.lift(cv).unwrap();
-                let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
-                p.pretty_print_const_valtree(cv, /*print_ty*/ true)?;
-                f.write_str(&p.into_buffer())
-            });
+            write!(f, "{}", cv)
+        } else {
+            // Fall back to something verbose.
+            write!(f, "{:?}", self.kind())
         }
-        // Fall back to something verbose.
-        write!(f, "{:?}", self.kind())
     }
 }