Skip to content

Commit da5b704

Browse files
committed
Auto merge of #119581 - Nadrieril:detangle-arena, r=<try>
Exhaustiveness: remove the need for arena-allocation within the algorithm WARNING: skip the first commit, it's from #119329 which is getting merged. This nicely cleans up the lifetime story: after this PR, all the `&'p DeconstructedPat` ever handled in the algorithm are coming from user input; we never build one ourselves. r? `@compiler-errors`
2 parents 090d5ea + 044ff22 commit da5b704

File tree

9 files changed

+275
-207
lines changed

9 files changed

+275
-207
lines changed

Cargo.lock

-7
Original file line numberDiff line numberDiff line change
@@ -4355,7 +4355,6 @@ dependencies = [
43554355
"rustc_target",
43564356
"smallvec",
43574357
"tracing",
4358-
"typed-arena",
43594358
]
43604359

43614360
[[package]]
@@ -5692,12 +5691,6 @@ dependencies = [
56925691
"rustc-hash",
56935692
]
56945693

5695-
[[package]]
5696-
name = "typed-arena"
5697-
version = "2.0.2"
5698-
source = "registry+https://github.com/rust-lang/crates.io-index"
5699-
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
5700-
57015694
[[package]]
57025695
name = "typenum"
57035696
version = "1.16.0"

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
554554
let cx = self.new_cx(refutability, None, scrut, pat.span);
555555
let pat = self.lower_pattern(&cx, pat)?;
556556
let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
557-
let report = analyze_match(&cx, &arms, pat.ty());
557+
let report = analyze_match(&cx, &arms, pat.ty().inner());
558558
Ok((cx, report))
559559
}
560560

@@ -972,7 +972,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
972972
}
973973
} else if ty == cx.tcx.types.str_ {
974974
err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary");
975-
} else if cx.is_foreign_non_exhaustive_enum(ty) {
975+
} else if cx.is_foreign_non_exhaustive_enum(cx.reveal_opaque_ty(ty)) {
976976
err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively"));
977977
}
978978
}
@@ -1112,12 +1112,12 @@ fn collect_non_exhaustive_tys<'tcx>(
11121112
non_exhaustive_tys: &mut FxIndexSet<Ty<'tcx>>,
11131113
) {
11141114
if matches!(pat.ctor(), Constructor::NonExhaustive) {
1115-
non_exhaustive_tys.insert(pat.ty());
1115+
non_exhaustive_tys.insert(pat.ty().inner());
11161116
}
11171117
if let Constructor::IntRange(range) = pat.ctor() {
11181118
if cx.is_range_beyond_boundaries(range, pat.ty()) {
11191119
// The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`.
1120-
non_exhaustive_tys.insert(pat.ty());
1120+
non_exhaustive_tys.insert(pat.ty().inner());
11211121
}
11221122
}
11231123
pat.iter_fields()

compiler/rustc_pattern_analysis/Cargo.toml

-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ rustc_span = { path = "../rustc_span", optional = true }
2020
rustc_target = { path = "../rustc_target", optional = true }
2121
smallvec = { version = "1.8.1", features = ["union"] }
2222
tracing = "0.1"
23-
typed-arena = { version = "2.0.2", optional = true }
2423
# tidy-alphabetical-end
2524

2625
[features]
@@ -41,6 +40,3 @@ rustc = [
4140
"smallvec/may_dangle",
4241
"rustc_index/nightly",
4342
]
44-
stable = [
45-
"dep:typed-arena",
46-
]

compiler/rustc_pattern_analysis/src/constructor.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ impl<Cx: TypeCx> Constructor<Cx> {
718718

719719
/// The number of fields for this constructor. This must be kept in sync with
720720
/// `Fields::wildcards`.
721-
pub(crate) fn arity(&self, pcx: &PlaceCtxt<'_, '_, Cx>) -> usize {
721+
pub(crate) fn arity(&self, pcx: &PlaceCtxt<'_, Cx>) -> usize {
722722
pcx.ctor_arity(self)
723723
}
724724

@@ -727,7 +727,7 @@ impl<Cx: TypeCx> Constructor<Cx> {
727727
/// this checks for inclusion.
728728
// We inline because this has a single call site in `Matrix::specialize_constructor`.
729729
#[inline]
730-
pub(crate) fn is_covered_by<'p>(&self, pcx: &PlaceCtxt<'_, 'p, Cx>, other: &Self) -> bool {
730+
pub(crate) fn is_covered_by(&self, pcx: &PlaceCtxt<'_, Cx>, other: &Self) -> bool {
731731
match (self, other) {
732732
(Wildcard, _) => pcx
733733
.mcx
@@ -861,7 +861,7 @@ impl<Cx: TypeCx> ConstructorSet<Cx> {
861861
#[instrument(level = "debug", skip(self, pcx, ctors), ret)]
862862
pub(crate) fn split<'a>(
863863
&self,
864-
pcx: &PlaceCtxt<'a, '_, Cx>,
864+
pcx: &PlaceCtxt<'a, Cx>,
865865
ctors: impl Iterator<Item = &'a Constructor<Cx>> + Clone,
866866
) -> SplitConstructorSet<Cx> {
867867
let mut present: SmallVec<[_; 1]> = SmallVec::new();

compiler/rustc_pattern_analysis/src/lib.rs

+3-15
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,6 @@ use crate::rustc::RustcMatchCheckCtxt;
3636
#[cfg(feature = "rustc")]
3737
use crate::usefulness::{compute_match_usefulness, ValidityConstraint};
3838

39-
// It's not possible to only enable the `typed_arena` dependency when the `rustc` feature is off, so
40-
// we use another feature instead. The crate won't compile if one of these isn't enabled.
41-
#[cfg(feature = "rustc")]
42-
pub(crate) use rustc_arena::TypedArena;
43-
#[cfg(feature = "stable")]
44-
pub(crate) use typed_arena::Arena as TypedArena;
45-
4639
pub trait Captures<'a> {}
4740
impl<'a, T: ?Sized> Captures<'a> for T {}
4841

@@ -61,8 +54,6 @@ pub trait TypeCx: Sized + fmt::Debug {
6154
/// Extra data to store in a pattern.
6255
type PatData: Clone;
6356

64-
/// FIXME(Nadrieril): `Cx` should only give us revealed types.
65-
fn reveal_opaque_ty(&self, ty: Self::Ty) -> Self::Ty;
6657
fn is_exhaustive_patterns_feature_on(&self) -> bool;
6758

6859
/// The number of fields for this constructor.
@@ -87,11 +78,9 @@ pub trait TypeCx: Sized + fmt::Debug {
8778
/// Context that provides information global to a match.
8879
#[derive(derivative::Derivative)]
8980
#[derivative(Clone(bound = ""), Copy(bound = ""))]
90-
pub struct MatchCtxt<'a, 'p, Cx: TypeCx> {
81+
pub struct MatchCtxt<'a, Cx: TypeCx> {
9182
/// The context for type information.
9283
pub tycx: &'a Cx,
93-
/// An arena to store the wildcards we produce during analysis.
94-
pub wildcard_arena: &'p TypedArena<DeconstructedPat<'p, Cx>>,
9584
}
9685

9786
/// The arm of a match expression.
@@ -112,10 +101,9 @@ pub fn analyze_match<'p, 'tcx>(
112101
arms: &[rustc::MatchArm<'p, 'tcx>],
113102
scrut_ty: Ty<'tcx>,
114103
) -> rustc::UsefulnessReport<'p, 'tcx> {
115-
// Arena to store the extra wildcards we construct during analysis.
116-
let wildcard_arena = tycx.pattern_arena;
104+
let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
117105
let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
118-
let cx = MatchCtxt { tycx, wildcard_arena };
106+
let cx = MatchCtxt { tycx };
119107

120108
let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity);
121109

compiler/rustc_pattern_analysis/src/lints.rs

+23-37
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use smallvec::SmallVec;
22

33
use rustc_data_structures::captures::Captures;
4-
use rustc_middle::ty::{self, Ty};
4+
use rustc_middle::ty;
55
use rustc_session::lint;
66
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
77
use rustc_span::Span;
@@ -11,11 +11,11 @@ use crate::errors::{
1111
NonExhaustiveOmittedPattern, NonExhaustiveOmittedPatternLintOnArm, Overlap,
1212
OverlappingRangeEndpoints, Uncovered,
1313
};
14+
use crate::pat::PatOrWild;
1415
use crate::rustc::{
15-
Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RustcMatchCheckCtxt,
16+
Constructor, DeconstructedPat, MatchArm, MatchCtxt, PlaceCtxt, RevealedTy, RustcMatchCheckCtxt,
1617
SplitConstructorSet, WitnessPat,
1718
};
18-
use crate::TypeCx;
1919

2020
/// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that
2121
/// inspect the same subvalue/place".
@@ -34,28 +34,24 @@ pub(crate) struct PatternColumn<'p, 'tcx> {
3434

3535
impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
3636
pub(crate) fn new(arms: &[MatchArm<'p, 'tcx>]) -> Self {
37-
let mut patterns = Vec::with_capacity(arms.len());
37+
let mut column = PatternColumn { patterns: Vec::with_capacity(arms.len()) };
3838
for arm in arms {
39-
if arm.pat.is_or_pat() {
40-
patterns.extend(arm.pat.flatten_or_pat())
41-
} else {
42-
patterns.push(arm.pat)
43-
}
39+
column.expand_and_push(PatOrWild::Pat(arm.pat));
4440
}
45-
Self { patterns }
46-
}
47-
48-
fn is_empty(&self) -> bool {
49-
self.patterns.is_empty()
41+
column
5042
}
51-
fn head_ty(&self, cx: MatchCtxt<'_, 'p, 'tcx>) -> Option<Ty<'tcx>> {
52-
if self.patterns.len() == 0 {
53-
return None;
43+
fn expand_and_push(&mut self, pat: PatOrWild<'p, RustcMatchCheckCtxt<'p, 'tcx>>) {
44+
if pat.is_or_pat() {
45+
self.patterns.extend(
46+
pat.flatten_or_pat().into_iter().filter_map(|pat_or_wild| pat_or_wild.as_pat()),
47+
)
48+
} else if let Some(pat) = pat.as_pat() {
49+
self.patterns.push(pat)
5450
}
51+
}
5552

56-
let ty = self.patterns[0].ty();
57-
// FIXME(Nadrieril): `Cx` should only give us revealed types.
58-
Some(cx.tycx.reveal_opaque_ty(ty))
53+
fn head_ty(&self) -> Option<RevealedTy<'tcx>> {
54+
self.patterns.first().map(|pat| pat.ty())
5955
}
6056

6157
/// Do constructor splitting on the constructors of the column.
@@ -91,21 +87,11 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
9187
let relevant_patterns =
9288
self.patterns.iter().filter(|pat| ctor.is_covered_by(pcx, pat.ctor()));
9389
for pat in relevant_patterns {
94-
let specialized = pat.specialize(pcx, ctor);
95-
for (subpat, column) in specialized.iter().zip(&mut specialized_columns) {
96-
if subpat.is_or_pat() {
97-
column.patterns.extend(subpat.flatten_or_pat())
98-
} else {
99-
column.patterns.push(subpat)
100-
}
90+
let specialized = pat.specialize(ctor, pcx.ctor_arity(ctor));
91+
for (subpat, column) in specialized.into_iter().zip(&mut specialized_columns) {
92+
column.expand_and_push(subpat);
10193
}
10294
}
103-
104-
assert!(
105-
!specialized_columns[0].is_empty(),
106-
"ctor {ctor:?} was listed as present but isn't;
107-
there is an inconsistency between `Constructor::is_covered_by` and `ConstructorSet::split`"
108-
);
10995
specialized_columns
11096
}
11197
}
@@ -117,7 +103,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
117103
cx: MatchCtxt<'a, 'p, 'tcx>,
118104
column: &PatternColumn<'p, 'tcx>,
119105
) -> Vec<WitnessPat<'p, 'tcx>> {
120-
let Some(ty) = column.head_ty(cx) else {
106+
let Some(ty) = column.head_ty() else {
121107
return Vec::new();
122108
};
123109
let pcx = &PlaceCtxt::new_dummy(cx, ty);
@@ -164,7 +150,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
164150
cx: MatchCtxt<'a, 'p, 'tcx>,
165151
arms: &[MatchArm<'p, 'tcx>],
166152
pat_column: &PatternColumn<'p, 'tcx>,
167-
scrut_ty: Ty<'tcx>,
153+
scrut_ty: RevealedTy<'tcx>,
168154
) {
169155
let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
170156
if !matches!(
@@ -182,7 +168,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
182168
rcx.match_lint_level,
183169
rcx.scrut_span,
184170
NonExhaustiveOmittedPattern {
185-
scrut_ty,
171+
scrut_ty: scrut_ty.inner(),
186172
uncovered: Uncovered::new(rcx.scrut_span, rcx, witnesses),
187173
},
188174
);
@@ -218,7 +204,7 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
218204
cx: MatchCtxt<'a, 'p, 'tcx>,
219205
column: &PatternColumn<'p, 'tcx>,
220206
) {
221-
let Some(ty) = column.head_ty(cx) else {
207+
let Some(ty) = column.head_ty() else {
222208
return;
223209
};
224210
let pcx = &PlaceCtxt::new_dummy(cx, ty);

0 commit comments

Comments
 (0)