From 3c7c4398121b5752431ea2727534b87e434ebc10 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 2 Jan 2026 13:32:49 +1100 Subject: [PATCH] Split out a separate `PatConstKind::String` --- compiler/rustc_middle/src/ty/sty.rs | 6 +++++ .../src/builder/matches/buckets.rs | 9 ++++++-- .../src/builder/matches/match_pair.rs | 15 +++++++++++- .../src/builder/matches/mod.rs | 23 ++++++++++++------- .../src/builder/matches/test.rs | 10 ++++---- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c3834607e923..c282f2211f65 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -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() { diff --git a/compiler/rustc_mir_build/src/builder/matches/buckets.rs b/compiler/rustc_mir_build/src/builder/matches/buckets.rs index fce35aa9ef30..0d2e9bf87585 100644 --- a/compiler/rustc_mir_build/src/builder/matches/buckets.rs +++ b/compiler/rustc_mir_build/src/builder/matches/buckets.rs @@ -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 { .. }, _, ) => { 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 386ca61a6124..f0114c2193c3 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -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 }; diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 421065a89411..9080e2ba801b 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -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. diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 3f402b2ae414..cb0e28c7234f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -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);