Skip to content

Commit 68cb418

Browse files
committed
initial prototype
1 parent 0df0662 commit 68cb418

File tree

3 files changed

+141
-7
lines changed

3 files changed

+141
-7
lines changed

compiler/rustc_middle/src/arena.rs

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ macro_rules! arena_types {
114114
[decode] specialization_graph: rustc_middle::traits::specialization_graph::Graph,
115115
[] crate_inherent_impls: rustc_middle::ty::CrateInherentImpls,
116116
[] hir_owner_nodes: rustc_hir::OwnerNodes<'tcx>,
117+
[] pats2: rustc_middle::thir::Pat<'tcx>,
117118
]);
118119
)
119120
}

compiler/rustc_mir_build/src/builder/matches/match_pair.rs

+129-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_middle::mir::*;
22
use rustc_middle::thir::{self, *};
33
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
4+
use rustc_span::Span;
45

56
use crate::builder::Builder;
67
use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
@@ -33,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3334
/// Used internally by [`MatchPairTree::for_pattern`].
3435
fn prefix_slice_suffix<'pat>(
3536
&mut self,
37+
src_path: &'pat Pat<'tcx>,
3638
match_pairs: &mut Vec<MatchPairTree<'pat, 'tcx>>,
3739
place: &PlaceBuilder<'tcx>,
3840
prefix: &'pat [Box<Pat<'tcx>>],
@@ -54,11 +56,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
5456
((prefix.len() + suffix.len()).try_into().unwrap(), false)
5557
};
5658

57-
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
58-
let elem =
59-
ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false };
60-
MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self)
61-
}));
59+
let mut prefix_opt = false;
60+
61+
if self.is_constant_pattern_subslice(prefix) && opt_slice.is_none() && suffix.len() == 0 {
62+
let elem_ty = prefix[0].ty;
63+
let prefix_valtree = self.simplify_const_pattern_slice_into_valtree(prefix);
64+
65+
if let Some(match_pair) = self.valtree_to_match_pair(
66+
src_path.ty,
67+
src_path.span,
68+
prefix.len() as u64,
69+
prefix_valtree,
70+
place.clone(),
71+
elem_ty,
72+
) {
73+
match_pairs.push(match_pair);
74+
prefix_opt = true;
75+
}
76+
}
77+
78+
if !prefix_opt {
79+
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
80+
let elem = ProjectionElem::ConstantIndex {
81+
offset: idx as u64,
82+
min_length,
83+
from_end: false,
84+
};
85+
MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self)
86+
}));
87+
}
6288

6389
if let Some(subslice_pat) = opt_slice {
6490
let suffix_len = suffix.len() as u64;
@@ -81,6 +107,88 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
81107
MatchPairTree::for_pattern(place, subpattern, self)
82108
}));
83109
}
110+
111+
fn is_constant_pattern_subslice(&self, subslice: &[Box<Pat<'tcx>>]) -> bool {
112+
subslice.len() > 1 && subslice.iter().all(|p| self.is_constant_pattern(p))
113+
}
114+
115+
fn is_constant_pattern(&self, pat: &Pat<'tcx>) -> bool {
116+
if let PatKind::Constant { value } = pat.kind
117+
&& let Const::Ty(_, const_) = value
118+
&& let ty::ConstKind::Value(ty, valtree) = const_.kind()
119+
&& let ty::ValTree::Leaf(scalar) = valtree
120+
&& self.tcx.types.u8 == ty
121+
&& scalar.to_u8() != b'_'
122+
{
123+
true
124+
} else {
125+
false
126+
}
127+
}
128+
129+
fn extract_leaf(&self, pat: &Pat<'tcx>) -> ty::ValTree<'tcx> {
130+
if let PatKind::Constant { value } = pat.kind
131+
&& let Const::Ty(_, const_) = value
132+
&& let ty::ConstKind::Value(_, valtree) = const_.kind()
133+
&& matches!(valtree, ty::ValTree::Leaf(_))
134+
{
135+
valtree
136+
} else {
137+
unreachable!()
138+
}
139+
}
140+
141+
fn simplify_const_pattern_slice_into_valtree(
142+
&self,
143+
subslice: &[Box<Pat<'tcx>>],
144+
) -> ty::ValTree<'tcx> {
145+
let leaves = subslice.iter().map(|p| self.extract_leaf(p));
146+
let interned = self.tcx.arena.alloc_from_iter(leaves);
147+
ty::ValTree::Branch(interned)
148+
}
149+
150+
fn valtree_to_match_pair<'pat>(
151+
&mut self,
152+
src_pat_ty: Ty<'tcx>,
153+
span: Span,
154+
subslice_len: u64,
155+
valtree: ty::ValTree<'tcx>,
156+
place: PlaceBuilder<'tcx>,
157+
elem_ty: Ty<'tcx>,
158+
) -> Option<MatchPairTree<'pat, 'tcx>> {
159+
let tcx = self.tcx;
160+
let (const_ty, pat_ty) = if src_pat_ty.is_slice() {
161+
(
162+
Ty::new_imm_ref(
163+
tcx,
164+
tcx.lifetimes.re_erased,
165+
Ty::new_array(tcx, elem_ty, subslice_len),
166+
),
167+
Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, Ty::new_slice(tcx, elem_ty)),
168+
)
169+
} else {
170+
let arr_ty = Ty::new_array(tcx, elem_ty, subslice_len);
171+
(arr_ty, arr_ty)
172+
};
173+
174+
let r#const = ty::Const::new(tcx, ty::ConstKind::Value(const_ty, valtree));
175+
let r#const2 = Const::Ty(const_ty, r#const);
176+
177+
let pattern = tcx.arena.alloc(Pat {
178+
ty: pat_ty,
179+
span,
180+
kind: PatKind::Constant { value: Const::Ty(const_ty, r#const) },
181+
});
182+
183+
let test_case = TestCase::Constant { value: r#const2 };
184+
185+
Some(MatchPairTree {
186+
place: Some(place.to_place(self)),
187+
test_case,
188+
subpairs: Vec::new(),
189+
pattern,
190+
})
191+
}
84192
}
85193

86194
impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
@@ -192,11 +300,25 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
192300
}
193301

194302
PatKind::Array { ref prefix, ref slice, ref suffix } => {
195-
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
303+
cx.prefix_slice_suffix(
304+
pattern,
305+
&mut subpairs,
306+
&place_builder,
307+
prefix,
308+
slice,
309+
suffix,
310+
);
196311
default_irrefutable()
197312
}
198313
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
199-
cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix);
314+
cx.prefix_slice_suffix(
315+
pattern,
316+
&mut subpairs,
317+
&place_builder,
318+
prefix,
319+
slice,
320+
suffix,
321+
);
200322

201323
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
202324
default_irrefutable()

compiler/rustc_mir_build/src/builder/matches/test.rs

+11
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
377377
) {
378378
let mut expect = self.literal_operand(source_info.span, value);
379379

380+
let ref_ty = Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, ty);
381+
let temp = self.temp(ty, source_info.span);
382+
self.cfg.push_assign(
383+
block,
384+
source_info,
385+
temp,
386+
Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, val),
387+
);
388+
ty = ref_ty;
389+
val = temp;
390+
380391
// If we're using `b"..."` as a pattern, we need to insert an
381392
// unsizing coercion, as the byte string has the type `&[u8; N]`.
382393
//

0 commit comments

Comments
 (0)