Skip to content

Commit 0c8ef47

Browse files
authored
Rollup merge of #71975 - nnethercote:reduce-TypedArena-creations-in-check_match, r=oli-obk
Reduce `TypedArena` creations in `check_match`. `check_match` creates a new `TypedArena` for every call to `create_and_enter`. DHAT tells me that each `TypedArena` typically is barely used, with typically a single allocation per arena. This commit moves the `TypedArena` creation outwards a bit, into `check_match`, and then passes it into `create_and_enter`. This reduces the number of arenas created by about 4-5x, for a very small perf win. (Moving the arena creation further outwards is hard because `check_match` is a query.) r? @oli-obk
2 parents e3a4ff0 + d26d187 commit 0c8ef47

File tree

2 files changed

+87
-93
lines changed

2 files changed

+87
-93
lines changed

src/librustc_mir_build/hair/pattern/_match.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -580,22 +580,11 @@ crate struct MatchCheckCtxt<'a, 'tcx> {
580580
/// outside it's module and should not be matchable with an empty match
581581
/// statement.
582582
crate module: DefId,
583-
param_env: ty::ParamEnv<'tcx>,
583+
crate param_env: ty::ParamEnv<'tcx>,
584584
crate pattern_arena: &'a TypedArena<Pat<'tcx>>,
585585
}
586586

587587
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
588-
crate fn create_and_enter<R>(
589-
tcx: TyCtxt<'tcx>,
590-
param_env: ty::ParamEnv<'tcx>,
591-
module: DefId,
592-
f: impl FnOnce(MatchCheckCtxt<'_, 'tcx>) -> R,
593-
) -> R {
594-
let pattern_arena = TypedArena::default();
595-
596-
f(MatchCheckCtxt { tcx, param_env, module, pattern_arena: &pattern_arena })
597-
}
598-
599588
fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
600589
if self.tcx.features().exhaustive_patterns {
601590
self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env)

src/librustc_mir_build/hair/pattern/check_match.rs

+86-81
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use super::_match::Usefulness::*;
22
use super::_match::WitnessPreference::*;
33
use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack};
4-
54
use super::{PatCtxt, PatKind, PatternError};
65

6+
use arena::TypedArena;
77
use rustc_ast::ast::Mutability;
88
use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder};
99
use rustc_hir as hir;
@@ -17,7 +17,6 @@ use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERN
1717
use rustc_session::parse::feature_err;
1818
use rustc_session::Session;
1919
use rustc_span::{sym, Span};
20-
2120
use std::slice;
2221

2322
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
@@ -26,8 +25,12 @@ crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
2625
Some(id) => tcx.hir().body_owned_by(tcx.hir().as_local_hir_id(id)),
2726
};
2827

29-
let mut visitor =
30-
MatchVisitor { tcx, tables: tcx.body_tables(body_id), param_env: tcx.param_env(def_id) };
28+
let mut visitor = MatchVisitor {
29+
tcx,
30+
tables: tcx.body_tables(body_id),
31+
param_env: tcx.param_env(def_id),
32+
pattern_arena: TypedArena::default(),
33+
};
3134
visitor.visit_body(tcx.hir().body(body_id));
3235
}
3336

@@ -39,6 +42,7 @@ struct MatchVisitor<'a, 'tcx> {
3942
tcx: TyCtxt<'tcx>,
4043
tables: &'a ty::TypeckTables<'tcx>,
4144
param_env: ty::ParamEnv<'tcx>,
45+
pattern_arena: TypedArena<super::Pat<'tcx>>,
4246
}
4347

4448
impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
@@ -143,9 +147,13 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
143147
(pattern, pattern_ty)
144148
}
145149

146-
fn check_in_cx(&self, hir_id: HirId, f: impl FnOnce(MatchCheckCtxt<'_, 'tcx>)) {
147-
let module = self.tcx.parent_module(hir_id);
148-
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module.to_def_id(), |cx| f(cx));
150+
fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'_, 'tcx> {
151+
MatchCheckCtxt {
152+
tcx: self.tcx,
153+
param_env: self.param_env,
154+
module: self.tcx.parent_module(hir_id).to_def_id(),
155+
pattern_arena: &self.pattern_arena,
156+
}
149157
}
150158

151159
fn check_match(
@@ -159,91 +167,88 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
159167
self.check_patterns(arm.guard.is_some(), &arm.pat);
160168
}
161169

162-
self.check_in_cx(scrut.hir_id, |ref mut cx| {
163-
let mut have_errors = false;
170+
let mut cx = self.new_cx(scrut.hir_id);
164171

165-
let inlined_arms: Vec<_> = arms
166-
.iter()
167-
.map(|hir::Arm { pat, guard, .. }| {
168-
(self.lower_pattern(cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some())
169-
})
170-
.collect();
172+
let mut have_errors = false;
171173

172-
// Bail out early if inlining failed.
173-
if have_errors {
174-
return;
175-
}
174+
let inlined_arms: Vec<_> = arms
175+
.iter()
176+
.map(|hir::Arm { pat, guard, .. }| {
177+
(self.lower_pattern(&mut cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some())
178+
})
179+
.collect();
180+
181+
// Bail out early if inlining failed.
182+
if have_errors {
183+
return;
184+
}
176185

177-
// Fourth, check for unreachable arms.
178-
let matrix = check_arms(cx, &inlined_arms, source);
186+
// Fourth, check for unreachable arms.
187+
let matrix = check_arms(&mut cx, &inlined_arms, source);
179188

180-
// Fifth, check if the match is exhaustive.
181-
let scrut_ty = self.tables.node_type(scrut.hir_id);
182-
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
183-
// since an empty matrix can occur when there are arms, if those arms all have guards.
184-
let is_empty_match = inlined_arms.is_empty();
185-
check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
186-
})
189+
// Fifth, check if the match is exhaustive.
190+
let scrut_ty = self.tables.node_type(scrut.hir_id);
191+
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
192+
// since an empty matrix can occur when there are arms, if those arms all have guards.
193+
let is_empty_match = inlined_arms.is_empty();
194+
check_exhaustive(&mut cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
187195
}
188196

189197
fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
190-
self.check_in_cx(pat.hir_id, |ref mut cx| {
191-
let (pattern, pattern_ty) = self.lower_pattern(cx, pat, &mut false);
192-
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
193-
194-
let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
195-
Ok(_) => return,
196-
Err(err) => err,
197-
};
198-
199-
let joined_patterns = joined_uncovered_patterns(&witnesses);
200-
let mut err = struct_span_err!(
201-
self.tcx.sess,
202-
pat.span,
203-
E0005,
204-
"refutable pattern in {}: {} not covered",
205-
origin,
206-
joined_patterns
207-
);
208-
let suggest_if_let = match &pat.kind {
209-
hir::PatKind::Path(hir::QPath::Resolved(None, path))
210-
if path.segments.len() == 1 && path.segments[0].args.is_none() =>
211-
{
212-
const_not_var(&mut err, cx.tcx, pat, path);
213-
false
214-
}
215-
_ => {
216-
err.span_label(
217-
pat.span,
218-
pattern_not_covered_label(&witnesses, &joined_patterns),
219-
);
220-
true
221-
}
222-
};
198+
let mut cx = self.new_cx(pat.hir_id);
223199

224-
if let (Some(span), true) = (sp, suggest_if_let) {
225-
err.note(
226-
"`let` bindings require an \"irrefutable pattern\", like a `struct` or \
227-
an `enum` with only one variant",
228-
);
229-
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
230-
err.span_suggestion(
231-
span,
232-
"you might want to use `if let` to ignore the variant that isn't matched",
233-
format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]),
234-
Applicability::HasPlaceholders,
235-
);
236-
}
237-
err.note(
238-
"for more information, visit \
239-
https://doc.rust-lang.org/book/ch18-02-refutability.html",
200+
let (pattern, pattern_ty) = self.lower_pattern(&mut cx, pat, &mut false);
201+
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
202+
203+
let witnesses = match check_not_useful(&mut cx, pattern_ty, &pats, pat.hir_id) {
204+
Ok(_) => return,
205+
Err(err) => err,
206+
};
207+
208+
let joined_patterns = joined_uncovered_patterns(&witnesses);
209+
let mut err = struct_span_err!(
210+
self.tcx.sess,
211+
pat.span,
212+
E0005,
213+
"refutable pattern in {}: {} not covered",
214+
origin,
215+
joined_patterns
216+
);
217+
let suggest_if_let = match &pat.kind {
218+
hir::PatKind::Path(hir::QPath::Resolved(None, path))
219+
if path.segments.len() == 1 && path.segments[0].args.is_none() =>
220+
{
221+
const_not_var(&mut err, cx.tcx, pat, path);
222+
false
223+
}
224+
_ => {
225+
err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns));
226+
true
227+
}
228+
};
229+
230+
if let (Some(span), true) = (sp, suggest_if_let) {
231+
err.note(
232+
"`let` bindings require an \"irrefutable pattern\", like a `struct` or \
233+
an `enum` with only one variant",
234+
);
235+
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
236+
err.span_suggestion(
237+
span,
238+
"you might want to use `if let` to ignore the variant that isn't matched",
239+
format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]),
240+
Applicability::HasPlaceholders,
240241
);
241242
}
243+
err.note(
244+
"for more information, visit \
245+
https://doc.rust-lang.org/book/ch18-02-refutability.html",
246+
);
247+
}
242248

243-
adt_defined_here(cx, &mut err, pattern_ty, &witnesses);
244-
err.note(&format!("the matched value is of type `{}`", pattern_ty));
245-
err.emit();
246-
});
249+
adt_defined_here(&mut cx, &mut err, pattern_ty, &witnesses);
250+
err.note(&format!("the matched value is of type `{}`", pattern_ty));
251+
err.emit();
247252
}
248253
}
249254

0 commit comments

Comments
 (0)