From 91451c422d34ad7dfe155ddfb0c28288f64fd389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Sun, 21 Sep 2025 17:50:38 +0200 Subject: [PATCH 01/16] add utils --- compiler/rustc_middle/src/arena.rs | 1 + .../src/builder/expr/as_place.rs | 4 ++ .../src/builder/matches/util.rs | 44 +++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 52fbe19c9f2d7..f2b4e2ae861f3 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -117,6 +117,7 @@ macro_rules! arena_types { [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, [] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls, [] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>, + [] thir_pats: rustc_middle::thir::Pat<'tcx>, ]); ) } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 5a6bd2f413c2d..871d007ba46c3 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -305,6 +305,10 @@ impl<'tcx> PlaceBuilder<'tcx> { &self.projection } + pub(crate) fn projection_mut(&mut self) -> &mut [PlaceElem<'tcx>] { + &mut self.projection + } + pub(crate) fn field(self, f: FieldIdx, ty: Ty<'tcx>) -> Self { self.project(PlaceElem::Field(f, ty)) } diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index 2c8ad95b6afdb..d6f073900f3d2 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -3,6 +3,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::Ty; use rustc_span::Span; use tracing::debug; +use std::ops; use crate::builder::Builder; use crate::builder::expr::as_place::PlaceBase; @@ -234,3 +235,46 @@ pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { Mutability::Not => BorrowKind::Shared, } } + +#[derive(Copy, Clone, PartialEq, Debug)] +pub(super) struct Range { + pub(super) start: u64, + pub(super) end: u64, + pub(super) from_end: bool, +} + +impl Range { + pub(super) fn from_start(range: ops::Range) -> Self { + Range { start: range.start, end: range.end, from_end: false } + } + + pub(super) fn from_end(range: ops::Range) -> Self { + Range { start: range.end, end: range.start, from_end: true } + } + + pub(super) fn len(self) -> u64 { + if !self.from_end { self.end - self.start } else { self.start - self.end } + } + + pub(super) fn apply(self, slice: &[T]) -> &[T] { + if !self.from_end { + &slice[self.start as usize..self.end as usize] + } else { + &slice[..self.start as usize - self.end as usize] + } + } + + pub(super) fn shift_idx(self, idx: u64) -> u64 { + if !self.from_end { self.start + idx } else { self.start - idx } + } + + pub(super) fn shift_range(self, range_within: ops::Range) -> Self { + if !self.from_end { + Self::from_start(self.start + range_within.start..self.start + range_within.end) + } else { + let range_within_start = range_within.end; + let range_within_end = range_within.start; + Self::from_end(self.start - range_within_start..self.start - range_within_end) + } + } +} From acb967b803f7637c52cc7be88c44e1a8a9b86e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Sun, 21 Sep 2025 18:00:16 +0200 Subject: [PATCH 02/16] add manip fns --- Cargo.lock | 1 + compiler/rustc_mir_build/Cargo.toml | 1 + .../src/builder/matches/match_pair.rs | 58 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c2e635b4cfe65..564c76ee67969 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4196,6 +4196,7 @@ dependencies = [ name = "rustc_mir_build" version = "0.0.0" dependencies = [ + "either", "itertools", "rustc_abi", "rustc_apfloat", diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index f756f0a19ee9b..bf888b3f7add7 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -5,6 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +either = "1.15.0" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" 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 7a848536d0e33..4eef4b5fda39c 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -4,6 +4,9 @@ use rustc_hir::ByRef; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::bug; +use either::Either; +use std::ops; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; @@ -84,6 +87,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) } } + + fn find_const_groups(&self, pattern: &[Box>]) -> Vec>> { + let mut entries = Vec::new(); + let mut current_seq_start = None; + + for (idx, pat) in pattern.iter().enumerate() { + if self.is_constant_pattern(pat) { + if current_seq_start.is_none() { + current_seq_start = Some(idx as u64); + } else { + continue; + } + } else { + if let Some(start) = current_seq_start { + entries.push(Either::Right(start..idx as u64)); + current_seq_start = None; + } + entries.push(Either::Left(idx as u64)); + } + } + + if let Some(start) = current_seq_start { + entries.push(Either::Right(start..pattern.len() as u64)); + } + + entries + } + + fn is_constant_pattern(&self, pat: &Pat<'tcx>) -> bool { + if let PatKind::Constant { value } = pat.kind + && let ty::ValTreeKind::Leaf(_) = &*value.valtree + { + true + } else { + false + } + } + + fn extract_leaf(&self, pat: &Pat<'tcx>) -> ty::ValTree<'tcx> { + if let PatKind::Constant { value } = pat.kind + && matches!(&*value.valtree, ty::ValTreeKind::Leaf(_)) + { + value.valtree + } else { + bug!("expected constant pattern, got {:?}", pat) + } + } + + fn simplify_const_pattern_slice_into_valtree( + &self, + subslice: &[Box>], + ) -> ty::ValTree<'tcx> { + let leaves = subslice.iter().map(|p| self.extract_leaf(p)); + ty::ValTree::from_branches(self.tcx, leaves) + } } impl<'tcx> MatchPairTree<'tcx> { From baf232551acaf4c36515f65493bafe061257d55a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 01:52:14 +0200 Subject: [PATCH 03/16] add match pair conv code --- .../src/builder/matches/match_pair.rs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) 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 4eef4b5fda39c..2565eb3d259ea 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -7,6 +7,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::bug; use either::Either; use std::ops; +use crate::builder::matches::util::Range; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; @@ -88,6 +89,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + fn valtree_to_match_pair( + &mut self, + source_pattern: &Pat<'tcx>, + valtree: ty::ValTree<'tcx>, + place: PlaceBuilder<'tcx>, + elem_ty: Ty<'tcx>, + range: Range, + min_length: u64, + ) -> MatchPairTree<'tcx> { + let tcx = self.tcx; + let ty = Ty::new_slice(tcx, elem_ty); + + let value = ty::Value { + ty, + valtree, + }; + + let place = place + .clone_project(ProjectionElem::ConstantIndex { + offset: range.start, + min_length, + from_end: range.from_end, + }) + .to_place(self); + + MatchPairTree { + place: Some(place), + test_case: TestCase::Constant { value }, + subpairs: vec![], + pattern_ty: source_pattern.ty, + pattern_span: source_pattern.span, + } + } + fn find_const_groups(&self, pattern: &[Box>]) -> Vec>> { let mut entries = Vec::new(); let mut current_seq_start = None; From ac432501dbdc168615a1d9c203c5d9ac2a36dc0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 03:05:02 +0200 Subject: [PATCH 04/16] slice branch build code --- .../src/builder/matches/match_pair.rs | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) 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 2565eb3d259ea..c93009799800d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -8,6 +8,7 @@ use rustc_middle::bug; use either::Either; use std::ops; use crate::builder::matches::util::Range; +use std::array; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; @@ -89,6 +90,61 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + fn build_slice_branch<'b, 'pat>( + &'b mut self, + bounds: Range, + place: &'b PlaceBuilder<'tcx>, + top_pattern: &'pat Pat<'tcx>, + pattern: &'pat [Box>], + min_length: u64, + ) -> impl Iterator> + use<'a, 'tcx, 'b, 'pat> { + let entries = self.find_const_groups(pattern); + + entries.into_iter().map(move |entry| { + let build_single = |idx| { + let subpattern = &pattern[idx as usize]; + let place = place.clone_project(ProjectionElem::ConstantIndex { + offset: bounds.shift_idx(idx), + min_length: pattern.len() as u64, + from_end: bounds.from_end, + }).to_place(self); + + let valtree = self.simplify_const_pattern_slice_into_valtree(array::from_ref(subpattern)); + let value = ty::Value { + ty: subpattern.ty, + valtree, + }; + + MatchPairTree { + place: Some(place), + test_case: TestCase::Constant { value }, + subpairs: vec![], + pattern_ty: top_pattern.ty, + pattern_span: top_pattern.span, + } + }; + + match entry { + Either::Right(range) if range.end - range.start > 1 => { + let subpattern = &pattern[range.start as usize..range.end as usize]; + let elem_ty = subpattern[0].ty; + + let valtree = self.simplify_const_pattern_slice_into_valtree(subpattern); + self.valtree_to_match_pair( + top_pattern, + valtree, + place.clone(), + elem_ty, + bounds.shift_range(range), + min_length, + ) + } + Either::Right(range) => build_single(range.start), + Either::Left(idx) => build_single(idx), + } + }) + } + fn valtree_to_match_pair( &mut self, source_pattern: &Pat<'tcx>, From 5df1868ea8354a820ae67c49c5a2aef6a0f04661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 03:47:43 +0200 Subject: [PATCH 05/16] cmp lowering --- .../src/builder/expr/as_place.rs | 4 - .../src/builder/matches/match_pair.rs | 94 ++++++++++--------- .../src/builder/matches/test.rs | 83 ++++++++++++++-- .../src/builder/matches/util.rs | 6 +- 4 files changed, 129 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 871d007ba46c3..5a6bd2f413c2d 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -305,10 +305,6 @@ impl<'tcx> PlaceBuilder<'tcx> { &self.projection } - pub(crate) fn projection_mut(&mut self) -> &mut [PlaceElem<'tcx>] { - &mut self.projection - } - pub(crate) fn field(self, f: FieldIdx, ty: Ty<'tcx>) -> Self { self.project(PlaceElem::Field(f, ty)) } 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 c93009799800d..dfc8d5a3c0cb1 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -8,7 +8,6 @@ use rustc_middle::bug; use either::Either; use std::ops; use crate::builder::matches::util::Range; -use std::array; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; @@ -39,6 +38,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Used internally by [`MatchPairTree::for_pattern`]. fn prefix_slice_suffix( &mut self, + top_pattern: &Pat<'tcx>, match_pairs: &mut Vec>, extra_data: &mut PatternExtraData<'tcx>, place: &PlaceBuilder<'tcx>, @@ -61,13 +61,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ((prefix.len() + suffix.len()).try_into().unwrap(), false) }; - for (idx, subpattern) in prefix.iter().enumerate() { - let elem = - ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - let place = place.clone_project(elem); - MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + if !prefix.is_empty() { + let bounds = Range::from_start(0..prefix.len() as u64); + let subpattern = bounds.apply(prefix); + self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); } + //for (idx, subpattern) in prefix.iter().enumerate() { + // let elem = + // ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; + // let place = place.clone_project(elem); + // MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + //} + if let Some(subslice_pat) = opt_slice { let suffix_len = suffix.len() as u64; let subslice = place.clone_project(PlaceElem::Subslice { @@ -78,50 +84,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data); } - for (idx, subpattern) in suffix.iter().rev().enumerate() { - let end_offset = (idx + 1) as u64; - let elem = ProjectionElem::ConstantIndex { - offset: if exact_size { min_length - end_offset } else { end_offset }, - min_length, - from_end: !exact_size, - }; - let place = place.clone_project(elem); - MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + if !suffix.is_empty() { + let bounds = Range::from_end(0..suffix.len() as u64); + let subpattern = bounds.apply(suffix); + self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); } + + //for (idx, subpattern) in suffix.iter().rev().enumerate() { + // let end_offset = (idx + 1) as u64; + // let elem = ProjectionElem::ConstantIndex { + // offset: if exact_size { min_length - end_offset } else { end_offset }, + // min_length, + // from_end: !exact_size, + // }; + // let place = place.clone_project(elem); + // MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + //} } - fn build_slice_branch<'b, 'pat>( + fn build_slice_branch<'b>( &'b mut self, + match_pairs: &mut Vec>, + extra_data: &mut PatternExtraData<'tcx>, bounds: Range, place: &'b PlaceBuilder<'tcx>, - top_pattern: &'pat Pat<'tcx>, - pattern: &'pat [Box>], + top_pattern: &Pat<'tcx>, + pattern: &[Pat<'tcx>], min_length: u64, - ) -> impl Iterator> + use<'a, 'tcx, 'b, 'pat> { + ) { let entries = self.find_const_groups(pattern); - entries.into_iter().map(move |entry| { - let build_single = |idx| { + entries.into_iter().for_each(move |entry| { + let mut build_single = |idx| { let subpattern = &pattern[idx as usize]; let place = place.clone_project(ProjectionElem::ConstantIndex { offset: bounds.shift_idx(idx), min_length: pattern.len() as u64, from_end: bounds.from_end, - }).to_place(self); - - let valtree = self.simplify_const_pattern_slice_into_valtree(array::from_ref(subpattern)); - let value = ty::Value { - ty: subpattern.ty, - valtree, - }; - - MatchPairTree { - place: Some(place), - test_case: TestCase::Constant { value }, - subpairs: vec![], - pattern_ty: top_pattern.ty, - pattern_span: top_pattern.span, - } + }); + + MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data); }; match entry { @@ -130,14 +132,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let elem_ty = subpattern[0].ty; let valtree = self.simplify_const_pattern_slice_into_valtree(subpattern); - self.valtree_to_match_pair( + let pair = self.valtree_to_match_pair( top_pattern, valtree, place.clone(), elem_ty, bounds.shift_range(range), min_length, - ) + ); + + match_pairs.push(pair); } Either::Right(range) => build_single(range.start), Either::Left(idx) => build_single(idx), @@ -155,8 +159,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { min_length: u64, ) -> MatchPairTree<'tcx> { let tcx = self.tcx; - let ty = Ty::new_slice(tcx, elem_ty); + let n = match &*valtree { + ty::ValTreeKind::Leaf(_) => unreachable!(), + ty::ValTreeKind::Branch(children) => children.len() as u64, + }; + let ty = Ty::new_array(tcx, elem_ty, n); let value = ty::Value { ty, valtree, @@ -174,12 +182,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: Some(place), test_case: TestCase::Constant { value }, subpairs: vec![], - pattern_ty: source_pattern.ty, + pattern_ty: ty, pattern_span: source_pattern.span, } } - fn find_const_groups(&self, pattern: &[Box>]) -> Vec>> { + fn find_const_groups(&self, pattern: &[Pat<'tcx>]) -> Vec>> { let mut entries = Vec::new(); let mut current_seq_start = None; @@ -228,7 +236,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn simplify_const_pattern_slice_into_valtree( &self, - subslice: &[Box>], + subslice: &[Pat<'tcx>], ) -> ty::ValTree<'tcx> { let leaves = subslice.iter().map(|p| self.extract_leaf(p)); ty::ValTree::from_branches(self.tcx, leaves) @@ -371,6 +379,7 @@ impl<'tcx> MatchPairTree<'tcx> { PatKind::Array { ref prefix, ref slice, ref suffix } => { cx.prefix_slice_suffix( + pattern, &mut subpairs, extra_data, &place_builder, @@ -382,6 +391,7 @@ impl<'tcx> MatchPairTree<'tcx> { } PatKind::Slice { ref prefix, ref slice, ref suffix } => { cx.prefix_slice_suffix( + pattern, &mut subpairs, extra_data, &place_builder, diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 1b6d96e49f0c1..cb3d1db3c5649 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -236,7 +236,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // (Interestingly this means that exhaustiveness analysis relies, for soundness, // on the `PartialEq` impl for `str` to b correct!) match *cast_ty.kind() { - ty::Ref(_, deref_ty, _) if deref_ty == self.tcx.types.str_ => {} + ty::Ref(_, deref_ty, _) if deref_ty == self.tcx.types.str_ => { + self.string_compare( + block, + success_block, + fail_block, + source_info, + expect, + Operand::Copy(place), + ); + }, + ty::Array(elem_ty, _) if elem_ty.is_scalar() => { + self.scalar_array_compare( + block, + success_block, + fail_block, + source_info, + expect, + Operand::Copy(place), + elem_ty, + ); + }, _ => { span_bug!( source_info.span, @@ -244,14 +264,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) } }; - self.string_compare( - block, - success_block, - fail_block, - source_info, - expect, - Operand::Copy(place), - ); } else { self.compare( block, @@ -487,6 +499,59 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } + fn scalar_array_compare( + &mut self, + block: BasicBlock, + success_block: BasicBlock, + fail_block: BasicBlock, + source_info: SourceInfo, + expect: Operand<'tcx>, + val: Operand<'tcx>, + item_ty: Ty<'tcx>, + ) { + let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, source_info.span); + let method = trait_method(self.tcx, eq_def_id, sym::eq, [item_ty, item_ty]); + + let bool_ty = self.tcx.types.bool; + let eq_result = self.temp(bool_ty, source_info.span); + let eq_block = self.cfg.start_new_block(); + self.cfg.terminate( + block, + source_info, + TerminatorKind::Call { + func: Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + + // FIXME(#54571): This constant comes from user input (a + // constant in a pattern). Are there forms where users can add + // type annotations here? For example, an associated constant? + // Need to experiment. + user_ty: None, + + const_: method, + })), + args: [ + Spanned { node: val, span: DUMMY_SP }, + Spanned { node: expect, span: DUMMY_SP }, + ] + .into(), + destination: eq_result, + target: Some(eq_block), + unwind: UnwindAction::Continue, + call_source: CallSource::MatchCmp, + fn_span: source_info.span, + }, + ); + self.diverge_from(block); + + // check the result + self.cfg.terminate( + eq_block, + source_info, + TerminatorKind::if_(Operand::Move(eq_result), success_block, fail_block), + ); + } + /// Given that we are performing `test` against `test_place`, this job /// sorts out what the status of `candidate` will be after the test. See /// `test_candidates` for the usage of this function. The candidate may diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index d6f073900f3d2..1b5369fc7149e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -252,9 +252,9 @@ impl Range { Range { start: range.end, end: range.start, from_end: true } } - pub(super) fn len(self) -> u64 { - if !self.from_end { self.end - self.start } else { self.start - self.end } - } + //pub(super) fn len(self) -> u64 { + // if !self.from_end { self.end - self.start } else { self.start - self.end } + //} pub(super) fn apply(self, slice: &[T]) -> &[T] { if !self.from_end { From fe2fe05f06939e75a08751253e8802c5d6dd1d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 07:49:07 +0200 Subject: [PATCH 06/16] work --- compiler/rustc_hir/src/lang_items.rs | 1 + .../src/builder/matches/match_pair.rs | 8 +-- .../src/builder/matches/test.rs | 66 ++++++++++++++----- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/cmp.rs | 15 +++++ 5 files changed, 69 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 2e099a97b65be..f599be96ab5b2 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -440,6 +440,7 @@ language_item_table! { // Reborrowing related lang-items Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0); + PatCmp, sym::pat_cmp, pat_cmp, Target::Fn, GenericRequirement::Exact(1); } /// The requirement imposed on the generics of a lang item 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 dfc8d5a3c0cb1..7140c79948ae3 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -156,7 +156,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: PlaceBuilder<'tcx>, elem_ty: Ty<'tcx>, range: Range, - min_length: u64, + _min_length: u64, ) -> MatchPairTree<'tcx> { let tcx = self.tcx; let n = match &*valtree { @@ -171,9 +171,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let place = place - .clone_project(ProjectionElem::ConstantIndex { - offset: range.start, - min_length, + .clone_project(ProjectionElem::Subslice { + from: range.start, + to: range.end, from_end: range.from_end, }) .to_place(self); diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index cb3d1db3c5649..08cac7912a9cd 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -246,15 +246,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Operand::Copy(place), ); }, - ty::Array(elem_ty, _) if elem_ty.is_scalar() => { + ty::Array(elem_ty, n) if elem_ty.is_scalar() => { self.scalar_array_compare( block, success_block, fail_block, source_info, expect, - Operand::Copy(place), + place, elem_ty, + n, ); }, _ => { @@ -506,11 +507,50 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fail_block: BasicBlock, source_info: SourceInfo, expect: Operand<'tcx>, - val: Operand<'tcx>, + val: Place<'tcx>, item_ty: Ty<'tcx>, + n: ty::Const<'tcx>, ) { - let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, source_info.span); - let method = trait_method(self.tcx, eq_def_id, sym::eq, [item_ty, item_ty]); + let pat_cmp_def_id = self.tcx.require_lang_item(LangItem::PatCmp, source_info.span); + let array_ty = Ty::new_array_with_const_len(self.tcx, item_ty, n); + let slice_ty = Ty::new_slice(self.tcx, item_ty); + let func = Operand::function_handle(self.tcx, pat_cmp_def_id, [array_ty.into()], source_info.span); + + let re_erased = self.tcx.lifetimes.re_erased; + let array_ref_ty = Ty::new_ref(self.tcx, re_erased, array_ty, ty::Mutability::Not); + //let slice_ref_ty = Ty::new_ref(self.tcx, re_erased, slice_ty, ty::Mutability::Not); + let array_ptr_ty = Ty::new_ptr(self.tcx, array_ty, ty::Mutability::Not); + let slice_ptr_ty = Ty::new_ptr(self.tcx, slice_ty, ty::Mutability::Not); + + let val_ref = match val.ty(&self.local_decls, self.tcx).ty.kind() { + ty::Array(_, _) => { + let val_ref = self.temp(array_ref_ty, source_info.span); + self.cfg.push_assign(block, source_info, val_ref, Rvalue::Ref(re_erased, BorrowKind::Shared, val)); + val_ref + }, + ty::Slice(_) => { + let val_slice_ptr = self.temp(slice_ptr_ty, source_info.span); + self.cfg.push_assign(block, source_info, val_slice_ptr, Rvalue::RawPtr(RawPtrKind::Const, val)); + let val_array_ptr = self.temp(array_ptr_ty, source_info.span); + self.cfg.push_assign( + block, + source_info, + val_array_ptr, + Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(val_slice_ptr), array_ptr_ty), + ); + + let val_array = val_array_ptr.project_deeper(&[PlaceElem::Deref], self.tcx); + let val_ref = self.temp(array_ref_ty, source_info.span); + self.cfg.push_assign(block, source_info, val_ref, Rvalue::Ref(re_erased, BorrowKind::Shared, val_array)); + val_ref + }, + _ => unreachable!(), + }; + + let expect_value = self.temp(array_ty, source_info.span); + self.cfg.push_assign(block, source_info, expect_value, Rvalue::Use(expect)); + let expect_ref = self.temp(array_ref_ty, source_info.span); + self.cfg.push_assign(block, source_info, expect_ref, Rvalue::Ref(re_erased, BorrowKind::Shared, expect_value)); let bool_ty = self.tcx.types.bool; let eq_result = self.temp(bool_ty, source_info.span); @@ -519,20 +559,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, TerminatorKind::Call { - func: Operand::Constant(Box::new(ConstOperand { - span: source_info.span, - - // FIXME(#54571): This constant comes from user input (a - // constant in a pattern). Are there forms where users can add - // type annotations here? For example, an associated constant? - // Need to experiment. - user_ty: None, - - const_: method, - })), + func, args: [ - Spanned { node: val, span: DUMMY_SP }, - Spanned { node: expect, span: DUMMY_SP }, + Spanned { node: Operand::Copy(val_ref), span: DUMMY_SP }, + Spanned { node: Operand::Copy(expect_ref), span: DUMMY_SP }, ] .into(), destination: eq_result, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4fef65f46b1fd..f13c57fab2f0c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1633,6 +1633,7 @@ symbols! { partial_ord, passes, pat, + pat_cmp, pat_param, patchable_function_entry, path, diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 7f369d19c3d12..842aebc27dab2 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -266,6 +266,21 @@ pub const trait PartialEq: PointeeSized { } } +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +#[rustc_const_stable_indirect] +#[rustc_allow_const_fn_unstable(const_cmp, const_trait_impl)] +const fn pat_cmp_impl(lhs: &T, rhs: &T) -> bool { + lhs.eq(rhs) +} + +#[lang = "pat_cmp"] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_stable(feature = "rust1", since = "1.0.0")] +#[rustc_allow_const_fn_unstable(const_cmp, const_trait_impl)] +const fn pat_cmp(lhs: &T, rhs: &T) -> bool { + pat_cmp_impl(lhs, rhs) +} + /// Derive macro generating an impl of the trait [`PartialEq`]. /// The behavior of this macro is described in detail [here](PartialEq#derivable). #[rustc_builtin_macro] From f7010975970295f2dc776fa36fa3f72a902bd4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 13:21:34 +0200 Subject: [PATCH 07/16] poc --- .../src/builder/matches/match_pair.rs | 81 ++++++++++++------- 1 file changed, 50 insertions(+), 31 deletions(-) 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 7140c79948ae3..2b8622fac5db0 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -61,19 +61,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ((prefix.len() + suffix.len()).try_into().unwrap(), false) }; - if !prefix.is_empty() { - let bounds = Range::from_start(0..prefix.len() as u64); - let subpattern = bounds.apply(prefix); - self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); + if opt_slice.is_none() && suffix.is_empty() { + if top_pattern.ty.is_slice() { + // new but with from_end + if !prefix.is_empty() { + let bounds = Range::from_start(0..prefix.len() as u64); + let subpattern = bounds.apply(prefix); + self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); + } + } else { + // new + if !prefix.is_empty() { + let bounds = Range::from_start(0..prefix.len() as u64); + let subpattern = bounds.apply(prefix); + self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); + } + } + } else { + // old + for (idx, subpattern) in prefix.iter().enumerate() { + let elem = + ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; + let place = place.clone_project(elem); + MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + } } - //for (idx, subpattern) in prefix.iter().enumerate() { - // let elem = - // ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - // let place = place.clone_project(elem); - // MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) - //} - if let Some(subslice_pat) = opt_slice { let suffix_len = suffix.len() as u64; let subslice = place.clone_project(PlaceElem::Subslice { @@ -84,22 +97,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data); } - if !suffix.is_empty() { - let bounds = Range::from_end(0..suffix.len() as u64); - let subpattern = bounds.apply(suffix); - self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); - } - - //for (idx, subpattern) in suffix.iter().rev().enumerate() { - // let end_offset = (idx + 1) as u64; - // let elem = ProjectionElem::ConstantIndex { - // offset: if exact_size { min_length - end_offset } else { end_offset }, - // min_length, - // from_end: !exact_size, - // }; - // let place = place.clone_project(elem); - // MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + //if !suffix.is_empty() { + // let bounds = Range::from_end(0..suffix.len() as u64); + // let subpattern = bounds.apply(suffix); + // self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); //} + + for (idx, subpattern) in suffix.iter().rev().enumerate() { + let end_offset = (idx + 1) as u64; + let elem = ProjectionElem::ConstantIndex { + offset: if exact_size { min_length - end_offset } else { end_offset }, + min_length, + from_end: !exact_size, + }; + let place = place.clone_project(elem); + MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + } } fn build_slice_branch<'b>( @@ -113,6 +126,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { min_length: u64, ) { let entries = self.find_const_groups(pattern); + let o_end = bounds.end; entries.into_iter().for_each(move |entry| { let mut build_single = |idx| { @@ -132,12 +146,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let elem_ty = subpattern[0].ty; let valtree = self.simplify_const_pattern_slice_into_valtree(subpattern); + let bounds = bounds.shift_range(range); let pair = self.valtree_to_match_pair( top_pattern, valtree, place.clone(), elem_ty, - bounds.shift_range(range), + bounds.start, + o_end - bounds.end, + true, // fix min_length, ); @@ -155,7 +172,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { valtree: ty::ValTree<'tcx>, place: PlaceBuilder<'tcx>, elem_ty: Ty<'tcx>, - range: Range, + from: u64, + to: u64, + from_end: bool, _min_length: u64, ) -> MatchPairTree<'tcx> { let tcx = self.tcx; @@ -172,9 +191,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = place .clone_project(ProjectionElem::Subslice { - from: range.start, - to: range.end, - from_end: range.from_end, + from, + to, + from_end, }) .to_place(self); From e654caf3acbc8560542d040a2d90ba79b7ab4107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 13:24:07 +0200 Subject: [PATCH 08/16] fmt --- .../src/builder/matches/match_pair.rs | 51 +++++++++++-------- .../src/builder/matches/test.rs | 39 ++++++++++---- .../src/builder/matches/util.rs | 3 +- 3 files changed, 63 insertions(+), 30 deletions(-) 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 2b8622fac5db0..6cb8dac9af716 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -1,16 +1,16 @@ +use std::ops; use std::sync::Arc; +use either::Either; use rustc_hir::ByRef; +use rustc_middle::bug; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; -use rustc_middle::bug; -use either::Either; -use std::ops; -use crate::builder::matches::util::Range; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; +use crate::builder::matches::util::Range; use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase}; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -67,21 +67,40 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if !prefix.is_empty() { let bounds = Range::from_start(0..prefix.len() as u64); let subpattern = bounds.apply(prefix); - self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); + self.build_slice_branch( + match_pairs, + extra_data, + bounds, + place, + top_pattern, + subpattern, + min_length, + ); } } else { // new if !prefix.is_empty() { let bounds = Range::from_start(0..prefix.len() as u64); let subpattern = bounds.apply(prefix); - self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); + self.build_slice_branch( + match_pairs, + extra_data, + bounds, + place, + top_pattern, + subpattern, + min_length, + ); } } } else { // old for (idx, subpattern) in prefix.iter().enumerate() { - let elem = - ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; + let elem = ProjectionElem::ConstantIndex { + offset: idx as u64, + min_length, + from_end: false, + }; let place = place.clone_project(elem); MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) } @@ -127,7 +146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { let entries = self.find_const_groups(pattern); let o_end = bounds.end; - + entries.into_iter().for_each(move |entry| { let mut build_single = |idx| { let subpattern = &pattern[idx as usize]; @@ -184,18 +203,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let ty = Ty::new_array(tcx, elem_ty, n); - let value = ty::Value { - ty, - valtree, - }; + let value = ty::Value { ty, valtree }; - let place = place - .clone_project(ProjectionElem::Subslice { - from, - to, - from_end, - }) - .to_place(self); + let place = + place.clone_project(ProjectionElem::Subslice { from, to, from_end }).to_place(self); MatchPairTree { place: Some(place), diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 08cac7912a9cd..6025af1aaa14b 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -245,7 +245,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expect, Operand::Copy(place), ); - }, + } ty::Array(elem_ty, n) if elem_ty.is_scalar() => { self.scalar_array_compare( block, @@ -257,7 +257,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { elem_ty, n, ); - }, + } _ => { span_bug!( source_info.span, @@ -514,7 +514,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let pat_cmp_def_id = self.tcx.require_lang_item(LangItem::PatCmp, source_info.span); let array_ty = Ty::new_array_with_const_len(self.tcx, item_ty, n); let slice_ty = Ty::new_slice(self.tcx, item_ty); - let func = Operand::function_handle(self.tcx, pat_cmp_def_id, [array_ty.into()], source_info.span); + let func = + Operand::function_handle(self.tcx, pat_cmp_def_id, [array_ty.into()], source_info.span); let re_erased = self.tcx.lifetimes.re_erased; let array_ref_ty = Ty::new_ref(self.tcx, re_erased, array_ty, ty::Mutability::Not); @@ -525,12 +526,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let val_ref = match val.ty(&self.local_decls, self.tcx).ty.kind() { ty::Array(_, _) => { let val_ref = self.temp(array_ref_ty, source_info.span); - self.cfg.push_assign(block, source_info, val_ref, Rvalue::Ref(re_erased, BorrowKind::Shared, val)); + self.cfg.push_assign( + block, + source_info, + val_ref, + Rvalue::Ref(re_erased, BorrowKind::Shared, val), + ); val_ref - }, + } ty::Slice(_) => { let val_slice_ptr = self.temp(slice_ptr_ty, source_info.span); - self.cfg.push_assign(block, source_info, val_slice_ptr, Rvalue::RawPtr(RawPtrKind::Const, val)); + self.cfg.push_assign( + block, + source_info, + val_slice_ptr, + Rvalue::RawPtr(RawPtrKind::Const, val), + ); let val_array_ptr = self.temp(array_ptr_ty, source_info.span); self.cfg.push_assign( block, @@ -541,16 +552,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let val_array = val_array_ptr.project_deeper(&[PlaceElem::Deref], self.tcx); let val_ref = self.temp(array_ref_ty, source_info.span); - self.cfg.push_assign(block, source_info, val_ref, Rvalue::Ref(re_erased, BorrowKind::Shared, val_array)); + self.cfg.push_assign( + block, + source_info, + val_ref, + Rvalue::Ref(re_erased, BorrowKind::Shared, val_array), + ); val_ref - }, + } _ => unreachable!(), }; let expect_value = self.temp(array_ty, source_info.span); self.cfg.push_assign(block, source_info, expect_value, Rvalue::Use(expect)); let expect_ref = self.temp(array_ref_ty, source_info.span); - self.cfg.push_assign(block, source_info, expect_ref, Rvalue::Ref(re_erased, BorrowKind::Shared, expect_value)); + self.cfg.push_assign( + block, + source_info, + expect_ref, + Rvalue::Ref(re_erased, BorrowKind::Shared, expect_value), + ); let bool_ty = self.tcx.types.bool; let eq_result = self.temp(bool_ty, source_info.span); diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index 1b5369fc7149e..a97f00f874f6d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -1,9 +1,10 @@ +use std::ops; + use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::*; use rustc_middle::ty::Ty; use rustc_span::Span; use tracing::debug; -use std::ops; use crate::builder::Builder; use crate::builder::expr::as_place::PlaceBase; From bac32a04a0f948c9d87b49e901ca7598e062fb26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 13:53:21 +0200 Subject: [PATCH 09/16] move subslicing into build_slice_branch --- .../src/builder/matches/match_pair.rs | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) 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 6cb8dac9af716..4543e455bcc7c 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -74,7 +74,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place, top_pattern, subpattern, - min_length, ); } } else { @@ -89,7 +88,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place, top_pattern, subpattern, - min_length, ); } } @@ -142,7 +140,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: &'b PlaceBuilder<'tcx>, top_pattern: &Pat<'tcx>, pattern: &[Pat<'tcx>], - min_length: u64, ) { let entries = self.find_const_groups(pattern); let o_end = bounds.end; @@ -166,15 +163,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let valtree = self.simplify_const_pattern_slice_into_valtree(subpattern); let bounds = bounds.shift_range(range); + + let place = + place.clone_project(ProjectionElem::Subslice { + from: bounds.start, + to: o_end - bounds.end, + from_end: true, + }).to_place(self); + let pair = self.valtree_to_match_pair( top_pattern, valtree, - place.clone(), + place, elem_ty, - bounds.start, - o_end - bounds.end, - true, // fix - min_length, ); match_pairs.push(pair); @@ -189,12 +190,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, source_pattern: &Pat<'tcx>, valtree: ty::ValTree<'tcx>, - place: PlaceBuilder<'tcx>, + place: Place<'tcx>, elem_ty: Ty<'tcx>, - from: u64, - to: u64, - from_end: bool, - _min_length: u64, ) -> MatchPairTree<'tcx> { let tcx = self.tcx; let n = match &*valtree { @@ -205,9 +202,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ty = Ty::new_array(tcx, elem_ty, n); let value = ty::Value { ty, valtree }; - let place = - place.clone_project(ProjectionElem::Subslice { from, to, from_end }).to_place(self); - MatchPairTree { place: Some(place), test_case: TestCase::Constant { value }, From 6dd0f46a64dd0135a67c0a06137bb142dc67825c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 14:27:35 +0200 Subject: [PATCH 10/16] partial refactor to remove range --- .../src/builder/matches/match_pair.rs | 53 ++++++------------- .../src/builder/matches/util.rs | 9 +++- 2 files changed, 23 insertions(+), 39 deletions(-) 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 4543e455bcc7c..c4c264ec9728f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -10,7 +10,6 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; -use crate::builder::matches::util::Range; use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase}; impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -61,35 +60,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ((prefix.len() + suffix.len()).try_into().unwrap(), false) }; - if opt_slice.is_none() && suffix.is_empty() { - if top_pattern.ty.is_slice() { - // new but with from_end - if !prefix.is_empty() { - let bounds = Range::from_start(0..prefix.len() as u64); - let subpattern = bounds.apply(prefix); - self.build_slice_branch( - match_pairs, - extra_data, - bounds, - place, - top_pattern, - subpattern, - ); - } - } else { - // new - if !prefix.is_empty() { - let bounds = Range::from_start(0..prefix.len() as u64); - let subpattern = bounds.apply(prefix); - self.build_slice_branch( - match_pairs, - extra_data, - bounds, - place, - top_pattern, - subpattern, - ); - } + if opt_slice.is_none() && suffix.is_empty() && top_pattern.ty.is_slice() { + // new + if !prefix.is_empty() { + self.build_slice_branch( + match_pairs, + extra_data, + false, + place, + top_pattern, + prefix, + ); } } else { // old @@ -136,21 +117,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &'b mut self, match_pairs: &mut Vec>, extra_data: &mut PatternExtraData<'tcx>, - bounds: Range, + _is_suffix: bool, place: &'b PlaceBuilder<'tcx>, top_pattern: &Pat<'tcx>, pattern: &[Pat<'tcx>], ) { let entries = self.find_const_groups(pattern); - let o_end = bounds.end; entries.into_iter().for_each(move |entry| { let mut build_single = |idx| { let subpattern = &pattern[idx as usize]; let place = place.clone_project(ProjectionElem::ConstantIndex { - offset: bounds.shift_idx(idx), + offset: idx, min_length: pattern.len() as u64, - from_end: bounds.from_end, + from_end: false, }); MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data); @@ -162,12 +142,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let elem_ty = subpattern[0].ty; let valtree = self.simplify_const_pattern_slice_into_valtree(subpattern); - let bounds = bounds.shift_range(range); let place = place.clone_project(ProjectionElem::Subslice { - from: bounds.start, - to: o_end - bounds.end, + from: range.start, + to: pattern.len() as u64 - range.end, from_end: true, }).to_place(self); diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index a97f00f874f6d..4c8128536f5b6 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -1,10 +1,9 @@ -use std::ops; - use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::*; use rustc_middle::ty::Ty; use rustc_span::Span; use tracing::debug; +use std::ops; use crate::builder::Builder; use crate::builder::expr::as_place::PlaceBase; @@ -237,6 +236,7 @@ pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { } } +#[allow(unused)] #[derive(Copy, Clone, PartialEq, Debug)] pub(super) struct Range { pub(super) start: u64, @@ -245,10 +245,12 @@ pub(super) struct Range { } impl Range { + #[allow(unused)] pub(super) fn from_start(range: ops::Range) -> Self { Range { start: range.start, end: range.end, from_end: false } } + #[allow(unused)] pub(super) fn from_end(range: ops::Range) -> Self { Range { start: range.end, end: range.start, from_end: true } } @@ -257,6 +259,7 @@ impl Range { // if !self.from_end { self.end - self.start } else { self.start - self.end } //} + #[allow(unused)] pub(super) fn apply(self, slice: &[T]) -> &[T] { if !self.from_end { &slice[self.start as usize..self.end as usize] @@ -265,10 +268,12 @@ impl Range { } } + #[allow(unused)] pub(super) fn shift_idx(self, idx: u64) -> u64 { if !self.from_end { self.start + idx } else { self.start - idx } } + #[allow(unused)] pub(super) fn shift_range(self, range_within: ops::Range) -> Self { if !self.from_end { Self::from_start(self.start + range_within.start..self.start + range_within.end) From a0f630d620cca59f7d22e9f5332dd42a04591d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 14:48:44 +0200 Subject: [PATCH 11/16] use merge opt when there is only a prefix slice pattern --- .../src/builder/matches/match_pair.rs | 49 ++++++++----------- .../src/builder/matches/util.rs | 3 +- 2 files changed, 23 insertions(+), 29 deletions(-) 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 c4c264ec9728f..4b97500521662 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -60,17 +60,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ((prefix.len() + suffix.len()).try_into().unwrap(), false) }; - if opt_slice.is_none() && suffix.is_empty() && top_pattern.ty.is_slice() { + if opt_slice.is_none() && suffix.is_empty() { // new if !prefix.is_empty() { - self.build_slice_branch( - match_pairs, - extra_data, - false, - place, - top_pattern, - prefix, - ); + self.build_slice_branch(match_pairs, extra_data, false, place, top_pattern, prefix); } } else { // old @@ -95,12 +88,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data); } - //if !suffix.is_empty() { - // let bounds = Range::from_end(0..suffix.len() as u64); - // let subpattern = bounds.apply(suffix); - // self.build_slice_branch(match_pairs, extra_data, bounds, place, top_pattern, subpattern, min_length); - //} - for (idx, subpattern) in suffix.iter().rev().enumerate() { let end_offset = (idx + 1) as u64; let elem = ProjectionElem::ConstantIndex { @@ -143,19 +130,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let valtree = self.simplify_const_pattern_slice_into_valtree(subpattern); - let place = - place.clone_project(ProjectionElem::Subslice { - from: range.start, - to: pattern.len() as u64 - range.end, - from_end: true, - }).to_place(self); - - let pair = self.valtree_to_match_pair( - top_pattern, - valtree, - place, - elem_ty, - ); + let place = if top_pattern.ty.is_slice() { + place + .clone_project(ProjectionElem::Subslice { + from: range.start, + to: pattern.len() as u64 - range.end, + from_end: true, + }) + .to_place(self) + } else { + place + .clone_project(ProjectionElem::Subslice { + from: range.start, + to: range.end, + from_end: false, + }) + .to_place(self) + }; + + let pair = self.valtree_to_match_pair(top_pattern, valtree, place, elem_ty); match_pairs.push(pair); } diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index 4c8128536f5b6..89d22e511679d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -1,9 +1,10 @@ +use std::ops; + use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::*; use rustc_middle::ty::Ty; use rustc_span::Span; use tracing::debug; -use std::ops; use crate::builder::Builder; use crate::builder::expr::as_place::PlaceBase; From c6e7e62a3aa7951929e7769f8071e65b9964da39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 15:21:49 +0200 Subject: [PATCH 12/16] enable it for trailing .. --- compiler/rustc_mir_build/src/builder/matches/match_pair.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4b97500521662..0c9a6a77f310a 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -60,7 +60,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ((prefix.len() + suffix.len()).try_into().unwrap(), false) }; - if opt_slice.is_none() && suffix.is_empty() { + if suffix.is_empty() { // new if !prefix.is_empty() { self.build_slice_branch(match_pairs, extra_data, false, place, top_pattern, prefix); From 1c77f2b4bf7cab4baa85cf1af80e6b9f90658c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 15:52:44 +0200 Subject: [PATCH 13/16] remove uneeded arena --- compiler/rustc_middle/src/arena.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index f2b4e2ae861f3..52fbe19c9f2d7 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -117,7 +117,6 @@ macro_rules! arena_types { [decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph, [] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls, [] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>, - [] thir_pats: rustc_middle::thir::Pat<'tcx>, ]); ) } From af50eec92fc3d69e7da4c4f737b9e980ad6b4bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 16:35:02 +0200 Subject: [PATCH 14/16] simplify pat_cmp lang item impl --- library/core/src/cmp.rs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 842aebc27dab2..62f9398b4952e 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -266,21 +266,6 @@ pub const trait PartialEq: PointeeSized { } } -#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] -#[rustc_const_stable_indirect] -#[rustc_allow_const_fn_unstable(const_cmp, const_trait_impl)] -const fn pat_cmp_impl(lhs: &T, rhs: &T) -> bool { - lhs.eq(rhs) -} - -#[lang = "pat_cmp"] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "rust1", since = "1.0.0")] -#[rustc_allow_const_fn_unstable(const_cmp, const_trait_impl)] -const fn pat_cmp(lhs: &T, rhs: &T) -> bool { - pat_cmp_impl(lhs, rhs) -} - /// Derive macro generating an impl of the trait [`PartialEq`]. /// The behavior of this macro is described in detail [here](PartialEq#derivable). #[rustc_builtin_macro] @@ -2274,3 +2259,11 @@ mod impls { } } } + +#[lang = "pat_cmp"] +#[rustc_const_stable_indirect] +#[rustc_allow_const_fn_unstable(const_cmp, const_trait_impl)] +#[inline(always)] +const fn pat_cmp(lhs: &T, rhs: &T) -> bool { + lhs.eq(rhs) +} From c5d7f5ac0c75300d6f053a3dea9ac5e563736bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 16:59:36 +0200 Subject: [PATCH 15/16] supply min_length to array --- .../src/builder/matches/match_pair.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) 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 0c9a6a77f310a..5d396e606a5ef 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -63,7 +63,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if suffix.is_empty() { // new if !prefix.is_empty() { - self.build_slice_branch(match_pairs, extra_data, false, place, top_pattern, prefix); + self.build_slice_branch( + match_pairs, + extra_data, + false, + place, + top_pattern, + prefix, + min_length, + ); } } else { // old @@ -108,6 +116,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place: &'b PlaceBuilder<'tcx>, top_pattern: &Pat<'tcx>, pattern: &[Pat<'tcx>], + min_length: u64, ) { let entries = self.find_const_groups(pattern); @@ -116,7 +125,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let subpattern = &pattern[idx as usize]; let place = place.clone_project(ProjectionElem::ConstantIndex { offset: idx, - min_length: pattern.len() as u64, + min_length, from_end: false, }); From 0f55e77c5eecd37eb1e59177181c56bac1e66337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Wejdenst=C3=A5l?= Date: Mon, 22 Sep 2025 17:03:21 +0200 Subject: [PATCH 16/16] remove unused code --- .../src/builder/matches/util.rs | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index 89d22e511679d..2c8ad95b6afdb 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -1,5 +1,3 @@ -use std::ops; - use rustc_data_structures::fx::FxIndexMap; use rustc_middle::mir::*; use rustc_middle::ty::Ty; @@ -236,52 +234,3 @@ pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { Mutability::Not => BorrowKind::Shared, } } - -#[allow(unused)] -#[derive(Copy, Clone, PartialEq, Debug)] -pub(super) struct Range { - pub(super) start: u64, - pub(super) end: u64, - pub(super) from_end: bool, -} - -impl Range { - #[allow(unused)] - pub(super) fn from_start(range: ops::Range) -> Self { - Range { start: range.start, end: range.end, from_end: false } - } - - #[allow(unused)] - pub(super) fn from_end(range: ops::Range) -> Self { - Range { start: range.end, end: range.start, from_end: true } - } - - //pub(super) fn len(self) -> u64 { - // if !self.from_end { self.end - self.start } else { self.start - self.end } - //} - - #[allow(unused)] - pub(super) fn apply(self, slice: &[T]) -> &[T] { - if !self.from_end { - &slice[self.start as usize..self.end as usize] - } else { - &slice[..self.start as usize - self.end as usize] - } - } - - #[allow(unused)] - pub(super) fn shift_idx(self, idx: u64) -> u64 { - if !self.from_end { self.start + idx } else { self.start - idx } - } - - #[allow(unused)] - pub(super) fn shift_range(self, range_within: ops::Range) -> Self { - if !self.from_end { - Self::from_start(self.start + range_within.start..self.start + range_within.end) - } else { - let range_within_start = range_within.end; - let range_within_end = range_within.start; - Self::from_end(self.start - range_within_start..self.start - range_within_end) - } - } -}