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
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
@@ -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};
@@ -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.
@@ -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>,
@@ -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 {
@@ -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,
@@ -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)]
@@ -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);
}
@@ -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(..)
@@ -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()
{
@@ -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,
@@ -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.
@@ -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,
@@ -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,
},

@@ -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 `!`.
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};
@@ -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| {
@@ -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) {
@@ -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) {
@@ -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))
}
}

Loading