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))
}
}

127 changes: 62 additions & 65 deletions compiler/rustc_mir_build/src/builder/matches/mod.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/builder/matches/simplify.rs
Original file line number Diff line number Diff line change
@@ -23,9 +23,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Simplify a list of match pairs so they all require a test. Stores relevant bindings and
/// ascriptions in `extra_data`.
#[instrument(skip(self), level = "debug")]
pub(super) fn simplify_match_pairs<'pat>(
pub(super) fn simplify_match_pairs(
&mut self,
match_pairs: &mut Vec<MatchPairTree<'pat, 'tcx>>,
match_pairs: &mut Vec<MatchPairTree<'tcx>>,
extra_data: &mut PatternExtraData<'tcx>,
) {
// In order to please the borrow checker, in a pattern like `x @ pat` we must lower the
21 changes: 11 additions & 10 deletions compiler/rustc_mir_build/src/builder/matches/test.rs
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
// the candidates based on the result.

use std::cmp::Ordering;
use std::sync::Arc;

use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::{LangItem, RangeEnd};
@@ -26,9 +27,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Identifies what test is needed to decide if `match_pair` is applicable.
///
/// It is a bug to call this with a not-fully-simplified pattern.
pub(super) fn pick_test_for_match_pair<'pat>(
pub(super) fn pick_test_for_match_pair(
&mut self,
match_pair: &MatchPairTree<'pat, 'tcx>,
match_pair: &MatchPairTree<'tcx>,
) -> Test<'tcx> {
let kind = match match_pair.test_case {
TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def },
@@ -37,9 +38,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => TestKind::SwitchInt,
TestCase::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern.ty },

TestCase::Range(range) => {
TestCase::Range(ref range) => {
assert_eq!(range.ty, match_pair.pattern.ty);
TestKind::Range(Box::new(range.clone()))
TestKind::Range(Arc::clone(range))
}

TestCase::Slice { len, variable_length } => {
@@ -521,8 +522,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self,
test_place: Place<'tcx>,
test: &Test<'tcx>,
candidate: &mut Candidate<'_, 'tcx>,
sorted_candidates: &FxIndexMap<TestBranch<'tcx>, Vec<&mut Candidate<'_, 'tcx>>>,
candidate: &mut Candidate<'tcx>,
sorted_candidates: &FxIndexMap<TestBranch<'tcx>, Vec<&mut Candidate<'tcx>>>,
) -> Option<TestBranch<'tcx>> {
// Find the match_pair for this place (if any). At present,
// afaik, there can be at most one. (In the future, if we
@@ -565,15 +566,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// a new value might invalidate that property for range patterns that
// have already been sorted into the failure arm, so we must take care
// not to add such values here.
let is_covering_range = |test_case: &TestCase<'_, 'tcx>| {
let is_covering_range = |test_case: &TestCase<'tcx>| {
test_case.as_range().is_some_and(|range| {
matches!(
range.contains(value, self.tcx, self.typing_env()),
None | Some(true)
)
})
};
let is_conflicting_candidate = |candidate: &&mut Candidate<'_, 'tcx>| {
let is_conflicting_candidate = |candidate: &&mut Candidate<'tcx>| {
candidate
.match_pairs
.iter()
@@ -685,8 +686,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

(TestKind::Range(test), &TestCase::Range(pat)) => {
if test.as_ref() == pat {
(TestKind::Range(test), TestCase::Range(pat)) => {
if test == pat {
fully_matched = true;
Some(TestBranch::Success)
} else {
8 changes: 4 additions & 4 deletions compiler/rustc_mir_build/src/builder/matches/util.rs
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// a MIR pass run after borrow checking.
pub(super) fn collect_fake_borrows<'tcx>(
cx: &mut Builder<'_, 'tcx>,
candidates: &[Candidate<'_, 'tcx>],
candidates: &[Candidate<'tcx>],
temp_span: Span,
scrutinee_base: PlaceBase,
) -> Vec<(Place<'tcx>, Local, FakeBorrowKind)> {
@@ -135,7 +135,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
}
}

fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) {
fn visit_candidate(&mut self, candidate: &Candidate<'tcx>) {
for binding in &candidate.extra_data.bindings {
self.visit_binding(binding);
}
@@ -144,7 +144,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
}
}

fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) {
fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'tcx>) {
for binding in &flat_pat.extra_data.bindings {
self.visit_binding(binding);
}
@@ -153,7 +153,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
}
}

fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'_, 'tcx>) {
fn visit_match_pair(&mut self, match_pair: &MatchPairTree<'tcx>) {
if let TestCase::Or { pats, .. } = &match_pair.test_case {
for flat_pat in pats.iter() {
self.visit_flat_pat(flat_pat)
4 changes: 3 additions & 1 deletion compiler/rustc_mir_build/src/thir/cx/block.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use rustc_hir as hir;
use rustc_index::Idx;
use rustc_middle::middle::region;
@@ -86,7 +88,7 @@ impl<'tcx> Cx<'tcx> {
span: ty.span,
inferred_ty: self.typeck_results.node_type(ty.hir_id),
};
pattern = Box::new(Pat {
pattern = Arc::new(Pat {
ty: pattern.ty,
span: pattern.span,
kind: PatKind::AscribeUserType {
4 changes: 3 additions & 1 deletion compiler/rustc_mir_build/src/thir/cx/mod.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@
//! structures into the THIR. The `builder` is generally ignorant of the tcx,
//! etc., and instead goes through the `Cx` for most of its work.
use std::sync::Arc;

use rustc_data_structures::steal::Steal;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
@@ -112,7 +114,7 @@ impl<'tcx> Cx<'tcx> {
}

#[instrument(level = "debug", skip(self))]
fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Arc<Pat<'tcx>> {
pat_from_hir(self.tcx, self.typing_env, self.typeck_results(), p)
}

41 changes: 18 additions & 23 deletions compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err
};

for param in thir.params.iter() {
if let Some(box ref pattern) = param.pat {
if let Some(ref pattern) = param.pat {
visitor.check_binding_is_irrefutable(pattern, origin, None, None);
}
}
@@ -155,7 +155,7 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => {
self.check_match(scrutinee, arms, match_source, ex.span);
}
ExprKind::Let { box ref pat, expr } => {
ExprKind::Let { ref pat, expr } => {
self.check_let(pat, Some(expr), ex.span);
}
ExprKind::LogicalOp { op: LogicalOp::And, .. }
@@ -176,9 +176,7 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {

fn visit_stmt(&mut self, stmt: &'p Stmt<'tcx>) {
match stmt.kind {
StmtKind::Let {
box ref pattern, initializer, else_block, lint_level, span, ..
} => {
StmtKind::Let { ref pattern, initializer, else_block, lint_level, span, .. } => {
self.with_lint_level(lint_level, |this| {
let let_source =
if else_block.is_some() { LetSource::LetElse } else { LetSource::PlainLet };
@@ -257,7 +255,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
ExprKind::Scope { value, lint_level, .. } => {
self.with_lint_level(lint_level, |this| this.visit_land_rhs(&this.thir[value]))
}
ExprKind::Let { box ref pat, expr } => {
ExprKind::Let { ref pat, expr } => {
let expr = &self.thir()[expr];
self.with_let_source(LetSource::None, |this| {
this.visit_expr(expr);
@@ -278,14 +276,14 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
cx: &PatCtxt<'p, 'tcx>,
pat: &'p Pat<'tcx>,
) -> Result<&'p DeconstructedPat<'p, 'tcx>, ErrorGuaranteed> {
if let Err(err) = pat.pat_error_reported() {
if let Err(err) = cx.thir.pat_error_reported(pat) {
self.error = Err(err);
Err(err)
} else {
// Check the pattern for some things unrelated to exhaustiveness.
let refutable = if cx.refutable { Refutable } else { Irrefutable };
let mut err = Ok(());
pat.walk_always(|pat| {
cx.thir.walk_pat_always(pat, |pat| {
check_borrow_conflicts_in_at_patterns(self, pat);
check_for_bindings_named_same_as_variants(self, pat, refutable);
err = err.and(check_never_pattern(cx, pat));
@@ -386,6 +384,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
scrutinee.map(|scrut| self.is_known_valid_scrutinee(scrut)).unwrap_or(true);
PatCtxt {
tcx: self.tcx,
thir: self.thir,
typeck_results: self.typeck_results,
typing_env: self.typing_env,
module: self.tcx.parent_module(self.lint_level).to_def_id(),
@@ -676,12 +675,12 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
let mut interpreted_as_const = None;
let mut interpreted_as_const_sugg = None;

if let PatKind::ExpandedConstant { def_id, is_inline: false, .. }
| PatKind::AscribeUserType {
subpattern:
box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. },
..
} = pat.kind
let mut subpat = pat;
while let PatKind::AscribeUserType { ref subpattern, .. } = subpat.kind {
subpat = subpattern;
}

if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = subpat.kind
&& let DefKind::Const = self.tcx.def_kind(def_id)
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
// We filter out paths with multiple path::segments.
@@ -692,11 +691,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
// When we encounter a constant as the binding name, point at the `const` definition.
interpreted_as_const = Some(span);
interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable });
} else if let PatKind::Constant { .. }
| PatKind::AscribeUserType {
subpattern: box Pat { kind: PatKind::Constant { .. }, .. },
..
} = pat.kind
} else if let PatKind::Constant { .. } = subpat.kind
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span)
{
// If the pattern to match is an integer literal:
@@ -714,7 +709,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
&& scrut.is_some()
{
let mut bindings = vec![];
pat.each_binding(|name, _, _, _| bindings.push(name));
self.thir.each_pat_binding(pat, |name, _, _, _| bindings.push(name));

let semi_span = span.shrink_to_hi();
let start_span = span.shrink_to_lo();
@@ -777,7 +772,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
/// This analysis is *not* subsumed by NLL.
fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: &Pat<'tcx>) {
// Extract `sub` in `binding @ sub`.
let PatKind::Binding { name, mode, ty, subpattern: Some(box ref sub), .. } = pat.kind else {
let PatKind::Binding { name, mode, ty, subpattern: Some(ref sub), .. } = pat.kind else {
return;
};

@@ -790,7 +785,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
ByRef::No if is_binding_by_move(ty) => {
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
let mut conflicts_ref = Vec::new();
sub.each_binding(|_, mode, _, span| {
cx.thir.each_pat_binding(sub, |_, mode, _, span| {
if matches!(mode, ByRef::Yes(_)) {
conflicts_ref.push(span)
}
@@ -819,7 +814,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
let mut conflicts_move = Vec::new();
let mut conflicts_mut_mut = Vec::new();
let mut conflicts_mut_ref = Vec::new();
sub.each_binding(|name, mode, ty, span| {
cx.thir.each_pat_binding(sub, |name, mode, ty, span| {
match mode {
ByRef::Yes(mut_inner) => match (mut_outer, mut_inner) {
// Both sides are `ref`.
13 changes: 7 additions & 6 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::ops::ControlFlow;
use std::sync::Arc;

use rustc_abi::{FieldIdx, VariantIdx};
use rustc_apfloat::Float;
@@ -41,7 +42,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
id: hir::HirId,
span: Span,
) -> Box<Pat<'tcx>> {
) -> Arc<Pat<'tcx>> {
let mut convert = ConstToPat::new(self, id, span, c);

match c.kind() {
@@ -84,7 +85,7 @@ impl<'tcx> ConstToPat<'tcx> {
}

/// We errored. Signal that in the pattern, so that follow up errors can be silenced.
fn mk_err(&self, mut err: Diag<'_>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
fn mk_err(&self, mut err: Diag<'_>, ty: Ty<'tcx>) -> Arc<Pat<'tcx>> {
if let ty::ConstKind::Unevaluated(uv) = self.c.kind() {
let def_kind = self.tcx.def_kind(uv.def);
if let hir::def::DefKind::AssocConst = def_kind
@@ -100,14 +101,14 @@ impl<'tcx> ConstToPat<'tcx> {
);
}
}
Box::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()) })
Arc::new(Pat { span: self.span, ty, kind: PatKind::Error(err.emit()) })
}

fn unevaluated_to_pat(
&mut self,
uv: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
) -> Box<Pat<'tcx>> {
) -> Arc<Pat<'tcx>> {
trace!(self.treat_byte_string_as_slice);

// It's not *technically* correct to be revealing opaque types here as borrowcheck has
@@ -216,7 +217,7 @@ impl<'tcx> ConstToPat<'tcx> {
// Recursive helper for `to_pat`; invoke that (instead of calling this directly).
// FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately.
#[instrument(skip(self), level = "debug")]
fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Arc<Pat<'tcx>> {
let span = self.span;
let tcx = self.tcx;
let kind = match ty.kind() {
@@ -363,7 +364,7 @@ impl<'tcx> ConstToPat<'tcx> {
}
};

Box::new(Pat { span, ty, kind })
Arc::new(Pat { span, ty, kind })
}
}

46 changes: 25 additions & 21 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ mod check_match;
mod const_to_pat;

use std::cmp::Ordering;
use std::sync::Arc;

use rustc_abi::{FieldIdx, Integer};
use rustc_errors::MultiSpan;
@@ -43,7 +44,7 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
typing_env: ty::TypingEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
pat: &'tcx hir::Pat<'tcx>,
) -> Box<Pat<'tcx>> {
) -> Arc<Pat<'tcx>> {
let mut pcx = PatCtxt {
tcx,
typing_env,
@@ -89,7 +90,7 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
}

impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Arc<Pat<'tcx>> {
// When implicit dereferences have been inserted in this pattern, the unadjusted lowered
// pattern has the type that results *after* dereferencing. For example, in this code:
//
@@ -122,7 +123,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
Box::new(Pat {
Arc::new(Pat {
span: thir_pat.span,
ty: *ref_ty,
kind: PatKind::Deref { subpattern: thir_pat },
@@ -164,12 +165,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
Some(expr) => {
let (kind, ascr, inline_const) = match self.lower_lit(expr) {
PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => {
(subpattern.kind, None, def_id.as_local())
let kind = Arc::unwrap_or_clone(subpattern).kind;
(kind, None, def_id.as_local())
}
PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => {
(subpattern.kind, None, None)
let kind = Arc::unwrap_or_clone(subpattern).kind;
(kind, None, None)
}
PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
PatKind::AscribeUserType { ascription, subpattern } => {
let kind = Arc::unwrap_or_clone(subpattern).kind;
(kind, Some(ascription), None)
}
kind => (kind, None, None),
@@ -260,7 +264,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity);

let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env);
let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty }));
let mut kind = PatKind::Range(Arc::new(PatRange { lo, hi, end, ty }));
match (end, cmp) {
// `x..y` where `x < y`.
(RangeEnd::Excluded, Some(Ordering::Less)) => {}
@@ -301,21 +305,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
for ascription in [lo_ascr, hi_ascr].into_iter().flatten() {
kind = PatKind::AscribeUserType {
ascription,
subpattern: Box::new(Pat { span, ty, kind }),
subpattern: Arc::new(Pat { span, ty, kind }),
};
}
for def in [lo_inline, hi_inline].into_iter().flatten() {
kind = PatKind::ExpandedConstant {
def_id: def.to_def_id(),
is_inline: true,
subpattern: Box::new(Pat { span, ty, kind }),
subpattern: Arc::new(Pat { span, ty, kind }),
};
}
Ok(kind)
}

#[instrument(skip(self), level = "debug")]
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Arc<Pat<'tcx>> {
let mut ty = self.typeck_results.node_type(pat.hir_id);
let mut span = pat.span;

@@ -426,12 +430,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },

// FIXME(guard_patterns): implement guard pattern lowering
hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind,
hir::PatKind::Guard(pat, _) => Arc::unwrap_or_clone(self.lower_pattern(pat)).kind,

hir::PatKind::Err(guar) => PatKind::Error(guar),
};

Box::new(Pat { span, ty, kind })
Arc::new(Pat { span, ty, kind })
}

fn lower_tuple_subpats(
@@ -449,11 +453,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
.collect()
}

fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box<Pat<'tcx>>]> {
fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Arc<Pat<'tcx>>]> {
pats.iter().map(|p| self.lower_pattern(p)).collect()
}

fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Box<Pat<'tcx>>> {
fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Arc<Pat<'tcx>>> {
pat.map(|p| self.lower_pattern(p))
}

@@ -562,7 +566,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
inferred_ty: self.typeck_results.node_type(hir_id),
};
kind = PatKind::AscribeUserType {
subpattern: Box::new(Pat { span, ty, kind }),
subpattern: Arc::new(Pat { span, ty, kind }),
ascription: Ascription { annotation, variance: ty::Covariant },
};
}
@@ -574,11 +578,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// it to `const_to_pat`. Any other path (like enum variants without fields)
/// is converted to the corresponding pattern via `lower_variant_or_leaf`.
#[instrument(skip(self), level = "debug")]
fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box<Pat<'tcx>> {
fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Arc<Pat<'tcx>> {
let ty = self.typeck_results.node_type(id);
let res = self.typeck_results.qpath_res(qpath, id);

let pat_from_kind = |kind| Box::new(Pat { span, ty, kind });
let pat_from_kind = |kind| Arc::new(Pat { span, ty, kind });

let (def_id, is_associated_const) = match res {
Res::Def(DefKind::Const, def_id) => (def_id, false),
@@ -590,7 +594,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let args = self.typeck_results.node_args(id);
let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args });
let subpattern = self.const_to_pat(c, ty, id, span);
let pattern = Box::new(Pat {
let pattern = Arc::new(Pat {
span,
ty,
kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false },
@@ -607,7 +611,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
span,
inferred_ty: self.typeck_results().node_type(id),
};
Box::new(Pat {
Arc::new(Pat {
span,
kind: PatKind::AscribeUserType {
subpattern: pattern,
@@ -655,7 +659,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_lit(&mut self, expr: &'tcx hir::PatExpr<'tcx>) -> PatKind<'tcx> {
let (lit, neg) = match &expr.kind {
hir::PatExprKind::Path(qpath) => {
return self.lower_path(qpath, expr.hir_id, expr.span).kind;
return Arc::unwrap_or_clone(self.lower_path(qpath, expr.hir_id, expr.span)).kind;
}
hir::PatExprKind::ConstBlock(anon_const) => {
return self.lower_inline_const(anon_const, expr.hir_id, expr.span);
@@ -666,7 +670,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let ct_ty = self.typeck_results.node_type(expr.hir_id);
let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg };
let constant = self.tcx.at(expr.span).lit_to_const(lit_input);
self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span).kind
Arc::unwrap_or_clone(self.const_to_pat(constant, ct_ty, expr.hir_id, lit.span)).kind
}
}

4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/thir/print.rs
Original file line number Diff line number Diff line change
@@ -643,8 +643,8 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, "}", depth_lvl);
}

fn print_pat(&mut self, pat: &Box<Pat<'tcx>>, depth_lvl: usize) {
let Pat { ty, span, kind } = &**pat;
fn print_pat(&mut self, pat: &Pat<'tcx>, depth_lvl: usize) {
let &Pat { ty, span, ref kind } = pat;

print_indented!(self, "Pat: {", depth_lvl);
print_indented!(self, format!("ty: {:?}", ty), depth_lvl + 1);
5 changes: 3 additions & 2 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
use rustc_index::{Idx, IndexVec};
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::mir::{self, Const};
use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary, Thir};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{
self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef,
@@ -76,8 +76,9 @@ impl<'tcx> RevealedTy<'tcx> {
}

#[derive(Clone)]
pub struct RustcPatCtxt<'p, 'tcx: 'p> {
pub struct RustcPatCtxt<'p, 'tcx> {
pub tcx: TyCtxt<'tcx>,
pub thir: &'p Thir<'tcx>,
pub typeck_results: &'tcx ty::TypeckResults<'tcx>,
/// The module in which the match occurs. This is necessary for
/// checking inhabited-ness of types because whether a type is (visibly)
3 changes: 2 additions & 1 deletion compiler/rustc_ty_utils/src/consts.rs
Original file line number Diff line number Diff line change
@@ -373,7 +373,8 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {

match pat.kind {
thir::PatKind::Constant { value } => value.has_non_region_param(),
thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => {
thir::PatKind::Range(ref range) => {
let &thir::PatRange { lo, hi, .. } = range.as_ref();
lo.has_non_region_param() || hi.has_non_region_param()
}
_ => false,