Split out a separate PatConstKind::String

This commit is contained in:
Zalathar 2026-01-02 13:32:49 +11:00
parent 91e169b1c9
commit 3c7c439812
5 changed files with 47 additions and 16 deletions

View file

@ -1218,6 +1218,12 @@ impl<'tcx> Ty<'tcx> {
*self.kind() == Str
}
/// Returns true if this type is `&str`. The reference's lifetime is ignored.
#[inline]
pub fn is_imm_ref_str(self) -> bool {
matches!(self.kind(), ty::Ref(_, inner, hir::Mutability::Not) if inner.is_str())
}
#[inline]
pub fn is_param(self, index: u32) -> bool {
match self.kind() {

View file

@ -314,7 +314,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
(
TestKind::Eq { value: test_val, .. },
TestKind::StringEq { value: test_val, .. },
TestableCase::Constant { value: case_val, kind: PatConstKind::String },
)
| (
TestKind::ScalarEq { value: test_val, .. },
TestableCase::Constant {
value: case_val,
kind: PatConstKind::Float | PatConstKind::Other,
@ -347,7 +351,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| TestKind::If
| TestKind::SliceLen { .. }
| TestKind::Range { .. }
| TestKind::Eq { .. }
| TestKind::StringEq { .. }
| TestKind::ScalarEq { .. }
| TestKind::Deref { .. },
_,
) => {

View file

@ -2,6 +2,7 @@ use std::sync::Arc;
use rustc_abi::FieldIdx;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::thir::*;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
@ -173,9 +174,21 @@ impl<'tcx> MatchPairTree<'tcx> {
PatConstKind::IntOrChar
} else if pat_ty.is_floating_point() {
PatConstKind::Float
} else if pat_ty.is_str() {
// Deref-patterns can cause string-literal patterns to have
// type `str` instead of the usual `&str`.
if !cx.tcx.features().deref_patterns() {
span_bug!(
pattern.span,
"const pattern has type `str` but deref_patterns is not enabled"
);
}
PatConstKind::String
} else if pat_ty.is_imm_ref_str() {
PatConstKind::String
} else {
// FIXME(Zalathar): This still covers several different
// categories (e.g. raw pointer, string, pattern-type)
// categories (e.g. raw pointer, pattern-type)
// which could be split out into their own kinds.
PatConstKind::Other
};

View file

@ -1290,9 +1290,10 @@ enum PatConstKind {
/// These types don't support `SwitchInt` and require an equality test,
/// but can also interact with range pattern tests.
Float,
/// Constant string values, tested via string equality.
String,
/// Any other constant-pattern is usually tested via some kind of equality
/// check. Types that might be encountered here include:
/// - `&str`
/// - raw pointers derived from integer values
/// - pattern types, e.g. `pattern_type!(u32 is 1..)`
Other,
@ -1368,14 +1369,20 @@ enum TestKind<'tcx> {
/// Test whether a `bool` is `true` or `false`.
If,
/// Test for equality with value, possibly after an unsizing coercion to
/// `cast_ty`,
Eq {
/// Tests the place against a string constant using string equality.
StringEq {
/// Constant `&str` value to test against.
value: ty::Value<'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` or floats.
cast_ty: Ty<'tcx>,
/// Type of the corresponding pattern node. Usually `&str`, but could
/// be `str` for patterns like `deref!("..."): String`.
pat_ty: Ty<'tcx>,
},
/// Tests the place against a constant using scalar equality.
ScalarEq {
value: ty::Value<'tcx>,
/// Type of the corresponding pattern node.
pat_ty: Ty<'tcx>,
},
/// Test whether the value falls within an inclusive or exclusive range.

View file

@ -38,11 +38,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TestableCase::Constant { value: _, kind: PatConstKind::IntOrChar } => {
TestKind::SwitchInt
}
TestableCase::Constant { value, kind: PatConstKind::Float } => {
TestKind::Eq { value, cast_ty: match_pair.pattern_ty }
TestableCase::Constant { value, kind: PatConstKind::String } => {
TestKind::StringEq { value, pat_ty: match_pair.pattern_ty }
}
TestableCase::Constant { value, kind: PatConstKind::Other } => {
TestKind::Eq { value, cast_ty: match_pair.pattern_ty }
TestableCase::Constant { value, kind: PatConstKind::Float | PatConstKind::Other } => {
TestKind::ScalarEq { value, pat_ty: match_pair.pattern_ty }
}
TestableCase::Range(ref range) => {
@ -141,7 +141,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
}
TestKind::Eq { value, cast_ty: pat_ty } => {
TestKind::StringEq { value, pat_ty } | TestKind::ScalarEq { value, pat_ty } => {
let tcx = self.tcx;
let success_block = target_block(TestBranch::Success);
let fail_block = target_block(TestBranch::Failure);