Skip to content

[DO NOT MERGE] Store THIR patterns in Arc instead of Box #136421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 47 additions & 38 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use std::cmp::Ordering;
use std::fmt;
use std::ops::Index;
use std::sync::Arc;

use rustc_abi::{FieldIdx, Integer, Size, VariantIdx};
use rustc_ast::{AsmMacro, InlineAsmOptions, InlineAsmTemplatePiece};
Expand Down Expand Up @@ -108,7 +109,7 @@ pub enum BodyTy<'tcx> {
#[derive(Clone, Debug, HashStable)]
pub struct Param<'tcx> {
/// The pattern that appears in the parameter list, or None for implicit parameters.
pub pat: Option<Box<Pat<'tcx>>>,
pub pat: Option<Arc<Pat<'tcx>>>,
/// The possibly inferred type.
pub ty: Ty<'tcx>,
/// Span of the explicitly provided type, or None if inferred for closures.
Expand Down Expand Up @@ -231,7 +232,7 @@ pub enum StmtKind<'tcx> {
/// `let <PAT> = ...`
///
/// If a type annotation is included, it is added as an ascription pattern.
pattern: Box<Pat<'tcx>>,
pattern: Arc<Pat<'tcx>>,

/// `let pat: ty = <INIT>`
initializer: Option<ExprId>,
Expand Down Expand Up @@ -379,7 +380,7 @@ pub enum ExprKind<'tcx> {
/// (Not to be confused with [`StmtKind::Let`], which is a normal `let` statement.)
Let {
expr: ExprId,
pat: Box<Pat<'tcx>>,
pat: Arc<Pat<'tcx>>,
},
/// A `match` expression.
Match {
Expand Down Expand Up @@ -571,7 +572,7 @@ pub struct FruInfo<'tcx> {
/// A `match` arm.
#[derive(Clone, Debug, HashStable)]
pub struct Arm<'tcx> {
pub pattern: Box<Pat<'tcx>>,
pub pattern: Arc<Pat<'tcx>>,
pub guard: Option<ExprId>,
pub body: ExprId,
pub lint_level: LintLevel,
Expand Down Expand Up @@ -628,7 +629,7 @@ pub enum InlineAsmOperand<'tcx> {
#[derive(Clone, Debug, HashStable, TypeVisitable)]
pub struct FieldPat<'tcx> {
pub field: FieldIdx,
pub pattern: Box<Pat<'tcx>>,
pub pattern: Arc<Pat<'tcx>>,
}

#[derive(Clone, Debug, HashStable, TypeVisitable)]
Expand All @@ -647,11 +648,17 @@ impl<'tcx> Pat<'tcx> {
_ => None,
}
}
}

impl<'tcx> Thir<'tcx> {
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
/// `match foo() { Some(a) => (), None => () }`
pub fn each_binding(&self, mut f: impl FnMut(Symbol, ByRef, Ty<'tcx>, Span)) {
self.walk_always(|p| {
pub fn each_pat_binding(
&self,
pat: &Pat<'tcx>,
mut f: impl FnMut(Symbol, ByRef, Ty<'tcx>, Span),
) {
self.walk_pat_always(pat, |p| {
if let PatKind::Binding { name, mode, ty, .. } = p.kind {
f(name, mode.0, ty, p.span);
}
Expand All @@ -661,17 +668,17 @@ impl<'tcx> Pat<'tcx> {
/// Walk the pattern in left-to-right order.
///
/// If `it(pat)` returns `false`, the children are not visited.
pub fn walk(&self, mut it: impl FnMut(&Pat<'tcx>) -> bool) {
self.walk_(&mut it)
pub fn walk_pat(&self, pat: &Pat<'tcx>, mut it: impl FnMut(&Pat<'tcx>) -> bool) {
self.walk_pat_inner(pat, &mut it);
}

fn walk_(&self, it: &mut impl FnMut(&Pat<'tcx>) -> bool) {
if !it(self) {
fn walk_pat_inner(&self, pat: &Pat<'tcx>, it: &mut impl FnMut(&Pat<'tcx>) -> bool) {
if !it(pat) {
return;
}

use PatKind::*;
match &self.kind {
match &pat.kind {
Wild
| Never
| Range(..)
Expand All @@ -682,22 +689,24 @@ impl<'tcx> Pat<'tcx> {
| Binding { subpattern: Some(subpattern), .. }
| Deref { subpattern }
| DerefPattern { subpattern, .. }
| ExpandedConstant { subpattern, .. } => subpattern.walk_(it),
| ExpandedConstant { subpattern, .. } => self.walk_pat_inner(subpattern, it),
Leaf { subpatterns } | Variant { subpatterns, .. } => {
subpatterns.iter().for_each(|field| field.pattern.walk_(it))
subpatterns.iter().for_each(|field| self.walk_pat_inner(&field.pattern, it))
}
Or { pats } => pats.iter().for_each(|p| p.walk_(it)),
Or { pats } => pats.iter().for_each(|p| self.walk_pat_inner(p, it)),
Array { box ref prefix, ref slice, box ref suffix }
| Slice { box ref prefix, ref slice, box ref suffix } => {
prefix.iter().chain(slice.iter()).chain(suffix.iter()).for_each(|p| p.walk_(it))
}
| Slice { box ref prefix, ref slice, box ref suffix } => prefix
.iter()
.chain(slice.iter())
.chain(suffix.iter())
.for_each(|p| self.walk_pat_inner(p, it)),
}
}

/// Whether the pattern has a `PatKind::Error` nested within.
pub fn pat_error_reported(&self) -> Result<(), ErrorGuaranteed> {
pub fn pat_error_reported(&self, pat: &Pat<'tcx>) -> Result<(), ErrorGuaranteed> {
let mut error = None;
self.walk(|pat| {
self.walk_pat(pat, |pat| {
if let PatKind::Error(e) = pat.kind
&& error.is_none()
{
Expand All @@ -714,23 +723,23 @@ impl<'tcx> Pat<'tcx> {
/// Walk the pattern in left-to-right order.
///
/// If you always want to recurse, prefer this method over `walk`.
pub fn walk_always(&self, mut it: impl FnMut(&Pat<'tcx>)) {
self.walk(|p| {
pub fn walk_pat_always(&self, pat: &Pat<'tcx>, mut it: impl FnMut(&Pat<'tcx>)) {
self.walk_pat(pat, |p| {
it(p);
true
})
}

/// Whether this a never pattern.
pub fn is_never_pattern(&self) -> bool {
pub fn is_never_pattern(&self, pat: &Pat<'tcx>) -> bool {
let mut is_never_pattern = false;
self.walk(|pat| match &pat.kind {
self.walk_pat(pat, |pat| match &pat.kind {
PatKind::Never => {
is_never_pattern = true;
false
}
PatKind::Or { pats } => {
is_never_pattern = pats.iter().all(|p| p.is_never_pattern());
is_never_pattern = pats.iter().all(|p| self.is_never_pattern(p));
false
}
_ => true,
Expand Down Expand Up @@ -770,7 +779,7 @@ pub enum PatKind<'tcx> {

AscribeUserType {
ascription: Ascription<'tcx>,
subpattern: Box<Pat<'tcx>>,
subpattern: Arc<Pat<'tcx>>,
},

/// `x`, `ref x`, `x @ P`, etc.
Expand All @@ -781,7 +790,7 @@ pub enum PatKind<'tcx> {
#[type_visitable(ignore)]
var: LocalVarId,
ty: Ty<'tcx>,
subpattern: Option<Box<Pat<'tcx>>>,
subpattern: Option<Arc<Pat<'tcx>>>,
/// Is this the leftmost occurrence of the binding, i.e., is `var` the
/// `HirId` of this pattern?
is_primary: bool,
Expand All @@ -804,12 +813,12 @@ pub enum PatKind<'tcx> {

/// `box P`, `&P`, `&mut P`, etc.
Deref {
subpattern: Box<Pat<'tcx>>,
subpattern: Arc<Pat<'tcx>>,
},

/// Deref pattern, written `box P` for now.
DerefPattern {
subpattern: Box<Pat<'tcx>>,
subpattern: Arc<Pat<'tcx>>,
mutability: hir::Mutability,
},

Expand Down Expand Up @@ -843,31 +852,31 @@ pub enum PatKind<'tcx> {
/// Otherwise, the actual pattern that the constant lowered to. As with
/// other constants, inline constants are matched structurally where
/// possible.
subpattern: Box<Pat<'tcx>>,
subpattern: Arc<Pat<'tcx>>,
},

Range(Box<PatRange<'tcx>>),
Range(Arc<PatRange<'tcx>>),

/// Matches against a slice, checking the length and extracting elements.
/// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
/// e.g., `&[ref xs @ ..]`.
Slice {
prefix: Box<[Box<Pat<'tcx>>]>,
slice: Option<Box<Pat<'tcx>>>,
suffix: Box<[Box<Pat<'tcx>>]>,
prefix: Box<[Arc<Pat<'tcx>>]>,
slice: Option<Arc<Pat<'tcx>>>,
suffix: Box<[Arc<Pat<'tcx>>]>,
},

/// Fixed match against an array; irrefutable.
Array {
prefix: Box<[Box<Pat<'tcx>>]>,
slice: Option<Box<Pat<'tcx>>>,
suffix: Box<[Box<Pat<'tcx>>]>,
prefix: Box<[Arc<Pat<'tcx>>]>,
slice: Option<Arc<Pat<'tcx>>>,
suffix: Box<[Arc<Pat<'tcx>>]>,
},

/// An or-pattern, e.g. `p | q`.
/// Invariant: `pats.len() >= 2`.
Or {
pats: Box<[Box<Pat<'tcx>>]>,
pats: Box<[Arc<Pat<'tcx>>]>,
},

/// A never pattern `!`.
Expand Down
28 changes: 16 additions & 12 deletions compiler/rustc_mir_build/src/builder/matches/match_pair.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use rustc_middle::mir::*;
use rustc_middle::thir::{self, *};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
Expand All @@ -12,11 +14,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// [`PatKind::Leaf`].
///
/// Used internally by [`MatchPairTree::for_pattern`].
fn field_match_pairs<'pat>(
fn field_match_pairs(
&mut self,
place: PlaceBuilder<'tcx>,
subpatterns: &'pat [FieldPat<'tcx>],
) -> Vec<MatchPairTree<'pat, 'tcx>> {
subpatterns: &[FieldPat<'tcx>],
) -> Vec<MatchPairTree<'tcx>> {
subpatterns
.iter()
.map(|fieldpat| {
Expand All @@ -31,13 +33,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// array pattern or slice pattern, and adds those trees to `match_pairs`.
///
/// Used internally by [`MatchPairTree::for_pattern`].
fn prefix_slice_suffix<'pat>(
fn prefix_slice_suffix(
&mut self,
match_pairs: &mut Vec<MatchPairTree<'pat, 'tcx>>,
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
place: &PlaceBuilder<'tcx>,
prefix: &'pat [Box<Pat<'tcx>>],
opt_slice: &'pat Option<Box<Pat<'tcx>>>,
suffix: &'pat [Box<Pat<'tcx>>],
prefix: &[Arc<Pat<'tcx>>],
opt_slice: &Option<Arc<Pat<'tcx>>>,
suffix: &[Arc<Pat<'tcx>>],
) {
let tcx = self.tcx;
let (min_length, exact_size) = if let Some(place_resolved) = place.try_to_place(self) {
Expand Down Expand Up @@ -83,14 +85,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
impl<'tcx> MatchPairTree<'tcx> {
/// Recursively builds a match pair tree for the given pattern and its
/// subpatterns.
pub(in crate::builder) fn for_pattern(
mut place_builder: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
pattern: &Arc<Pat<'tcx>>,
cx: &mut Builder<'_, 'tcx>,
) -> MatchPairTree<'pat, 'tcx> {
) -> MatchPairTree<'tcx> {
let pattern = Arc::clone(pattern);

// Force the place type to the pattern's type.
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
if let Some(resolved) = place_builder.resolve_upvar(cx) {
Expand Down Expand Up @@ -125,7 +129,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> {
if range.is_full_range(cx.tcx) == Some(true) {
default_irrefutable()
} else {
TestCase::Range(range)
TestCase::Range(Arc::clone(range))
}
}

Expand Down
Loading
Loading