Skip to content

Commit

Permalink
initial prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
xacrimon committed Jan 27, 2025
1 parent 0df0662 commit 68cb418
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 7 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
]);
)
}
Expand Down
136 changes: 129 additions & 7 deletions compiler/rustc_mir_build/src/builder/matches/match_pair.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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<MatchPairTree<'pat, 'tcx>>,
place: &PlaceBuilder<'tcx>,
prefix: &'pat [Box<Pat<'tcx>>],
Expand All @@ -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;
Expand All @@ -81,6 +107,88 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
MatchPairTree::for_pattern(place, subpattern, self)
}));
}

fn is_constant_pattern_subslice(&self, subslice: &[Box<Pat<'tcx>>]) -> 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<Pat<'tcx>>],
) -> 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<MatchPairTree<'pat, 'tcx>> {
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> {
Expand Down Expand Up @@ -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()
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_mir_build/src/builder/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]`.
//
Expand Down

0 comments on commit 68cb418

Please sign in to comment.