diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 750531b638e4d..cb195d8d51dd0 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -114,6 +114,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>, + [] pats2: rustc_middle::thir::Pat<'tcx>, ]); ) } 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 9d59ffc88ba23..bb2fd5d4782ce 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -1,6 +1,7 @@ use rustc_middle::mir::*; use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_span::Span; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; @@ -33,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// Used internally by [`MatchPairTree::for_pattern`]. fn prefix_slice_suffix<'pat>( &mut self, + src_path: &'pat Pat<'tcx>, match_pairs: &mut Vec>, place: &PlaceBuilder<'tcx>, prefix: &'pat [Box>], @@ -54,11 +56,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ((prefix.len() + suffix.len()).try_into().unwrap(), false) }; - match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { - let elem = - ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self) - })); + let mut prefix_opt = false; + + if self.is_constant_pattern_subslice(prefix) && opt_slice.is_none() && suffix.len() == 0 { + let elem_ty = prefix[0].ty; + let prefix_valtree = self.simplify_const_pattern_slice_into_valtree(prefix); + + if let Some(match_pair) = self.valtree_to_match_pair( + src_path.ty, + src_path.span, + prefix.len() as u64, + prefix_valtree, + place.clone(), + elem_ty, + ) { + match_pairs.push(match_pair); + prefix_opt = true; + } + } + + if !prefix_opt { + match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { + let elem = ProjectionElem::ConstantIndex { + offset: idx as u64, + min_length, + from_end: false, + }; + MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self) + })); + } if let Some(subslice_pat) = opt_slice { let suffix_len = suffix.len() as u64; @@ -81,6 +107,88 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { MatchPairTree::for_pattern(place, subpattern, self) })); } + + fn is_constant_pattern_subslice(&self, subslice: &[Box>]) -> bool { + subslice.len() > 1 && subslice.iter().all(|p| self.is_constant_pattern(p)) + } + + fn is_constant_pattern(&self, pat: &Pat<'tcx>) -> bool { + if let PatKind::Constant { value } = pat.kind + && let Const::Ty(_, const_) = value + && let ty::ConstKind::Value(ty, valtree) = const_.kind() + && let ty::ValTree::Leaf(scalar) = valtree + && self.tcx.types.u8 == ty + && scalar.to_u8() != b'_' + { + true + } else { + false + } + } + + fn extract_leaf(&self, pat: &Pat<'tcx>) -> ty::ValTree<'tcx> { + if let PatKind::Constant { value } = pat.kind + && let Const::Ty(_, const_) = value + && let ty::ConstKind::Value(_, valtree) = const_.kind() + && matches!(valtree, ty::ValTree::Leaf(_)) + { + valtree + } else { + unreachable!() + } + } + + fn simplify_const_pattern_slice_into_valtree( + &self, + subslice: &[Box>], + ) -> ty::ValTree<'tcx> { + let leaves = subslice.iter().map(|p| self.extract_leaf(p)); + let interned = self.tcx.arena.alloc_from_iter(leaves); + ty::ValTree::Branch(interned) + } + + fn valtree_to_match_pair<'pat>( + &mut self, + src_pat_ty: Ty<'tcx>, + span: Span, + subslice_len: u64, + valtree: ty::ValTree<'tcx>, + place: PlaceBuilder<'tcx>, + elem_ty: Ty<'tcx>, + ) -> Option> { + let tcx = self.tcx; + let (const_ty, pat_ty) = if src_pat_ty.is_slice() { + ( + Ty::new_imm_ref( + tcx, + tcx.lifetimes.re_erased, + Ty::new_array(tcx, elem_ty, subslice_len), + ), + Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, Ty::new_slice(tcx, elem_ty)), + ) + } else { + let arr_ty = Ty::new_array(tcx, elem_ty, subslice_len); + (arr_ty, arr_ty) + }; + + let r#const = ty::Const::new(tcx, ty::ConstKind::Value(const_ty, valtree)); + let r#const2 = Const::Ty(const_ty, r#const); + + let pattern = tcx.arena.alloc(Pat { + ty: pat_ty, + span, + kind: PatKind::Constant { value: Const::Ty(const_ty, r#const) }, + }); + + let test_case = TestCase::Constant { value: r#const2 }; + + Some(MatchPairTree { + place: Some(place.to_place(self)), + test_case, + subpairs: Vec::new(), + pattern, + }) + } } impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { @@ -192,11 +300,25 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { } PatKind::Array { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + cx.prefix_slice_suffix( + pattern, + &mut subpairs, + &place_builder, + prefix, + slice, + suffix, + ); default_irrefutable() } PatKind::Slice { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + cx.prefix_slice_suffix( + pattern, + &mut subpairs, + &place_builder, + prefix, + slice, + suffix, + ); if prefix.is_empty() && slice.is_some() && suffix.is_empty() { default_irrefutable() diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 8cca84d7fcc64..df60f12e2c652 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -377,6 +377,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { let mut expect = self.literal_operand(source_info.span, value); + let ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, ty); + let temp = self.temp(ty, source_info.span); + self.cfg.push_assign( + block, + source_info, + temp, + Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, val), + ); + ty = ref_ty; + val = temp; + // If we're using `b"..."` as a pattern, we need to insert an // unsizing coercion, as the byte string has the type `&[u8; N]`. //