Skip to content

Commit b7972e5

Browse files
committed
Auto merge of #16533 - Nadrieril:update-pat-ana, r=HKalbasi
Update to latest `rustc_pattern_analysis` Here I go again. Two improvements this time. 1. I've removed the need for an arena for patterns. Turns out this wasn't gaining any performance on the rustc side so may as well allocate normally. 2. I've added a clean error path when types don't match, so rustc_pattern_analysis should never panic except internal logic errors. For now `cx.bug()` calls `never!()` but I'm not sure what `never!()` does. Does it display anything to the user? Otherwise a `debug!()` should be sufficient. Point 2 should fix #15883 but I haven't tested it because I'm not sure how to reproduce. Could someone give me pointers as to how to write a test for the pattern code?
2 parents c06ca6c + 43caf83 commit b7972e5

File tree

5 files changed

+52
-43
lines changed

5 files changed

+52
-43
lines changed

Cargo.lock

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ ra-ap-rustc_lexer = { version = "0.35.0", default-features = false }
8484
ra-ap-rustc_parse_format = { version = "0.35.0", default-features = false }
8585
ra-ap-rustc_index = { version = "0.35.0", default-features = false }
8686
ra-ap-rustc_abi = { version = "0.35.0", default-features = false }
87-
ra-ap-rustc_pattern_analysis = { version = "0.36.0", default-features = false }
87+
ra-ap-rustc_pattern_analysis = { version = "0.37.0", default-features = false }
8888

8989
# local crates that aren't published to crates.io. These should not have versions.
9090
sourcegen = { path = "./crates/sourcegen" }

crates/hir-ty/src/diagnostics/expr.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ impl ExprValidator {
169169
return;
170170
}
171171

172-
let pattern_arena = Arena::new();
173-
let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena);
172+
let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db);
174173

174+
let pattern_arena = Arena::new();
175175
let mut m_arms = Vec::with_capacity(arms.len());
176176
let mut has_lowering_errors = false;
177177
for arm in arms {
@@ -196,8 +196,9 @@ impl ExprValidator {
196196
// If we had a NotUsefulMatchArm diagnostic, we could
197197
// check the usefulness of each pattern as we added it
198198
// to the matrix here.
199+
let pat = self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors);
199200
let m_arm = pat_analysis::MatchArm {
200-
pat: self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors),
201+
pat: pattern_arena.alloc(pat),
201202
has_guard: arm.guard.is_some(),
202203
arm_data: (),
203204
};
@@ -223,7 +224,7 @@ impl ExprValidator {
223224
ValidityConstraint::ValidOnly,
224225
) {
225226
Ok(report) => report,
226-
Err(void) => match void {},
227+
Err(()) => return,
227228
};
228229

229230
// FIXME Report unreachable arms
@@ -245,10 +246,10 @@ impl ExprValidator {
245246
db: &dyn HirDatabase,
246247
body: &Body,
247248
have_errors: &mut bool,
248-
) -> &'p DeconstructedPat<'p> {
249+
) -> DeconstructedPat<'p> {
249250
let mut patcx = match_check::PatCtxt::new(db, &self.infer, body);
250251
let pattern = patcx.lower_pattern(pat);
251-
let pattern = cx.pattern_arena.alloc(cx.lower_pat(&pattern));
252+
let pattern = cx.lower_pat(&pattern);
252253
if !patcx.errors.is_empty() {
253254
*have_errors = true;
254255
}

crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs

+18-28
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Interface with `rustc_pattern_analysis`.
22
33
use std::fmt;
4+
use tracing::debug;
45

56
use hir_def::{DefWithBodyId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
67
use rustc_hash::FxHashMap;
@@ -11,7 +12,6 @@ use rustc_pattern_analysis::{
1112
};
1213
use smallvec::{smallvec, SmallVec};
1314
use stdx::never;
14-
use typed_arena::Arena;
1515

1616
use crate::{
1717
db::HirDatabase,
@@ -26,7 +26,7 @@ use Constructor::*;
2626

2727
// Re-export r-a-specific versions of all these types.
2828
pub(crate) type DeconstructedPat<'p> =
29-
rustc_pattern_analysis::pat::DeconstructedPat<'p, MatchCheckCtx<'p>>;
29+
rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'p>>;
3030
pub(crate) type MatchArm<'p> = rustc_pattern_analysis::MatchArm<'p, MatchCheckCtx<'p>>;
3131
pub(crate) type WitnessPat<'p> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'p>>;
3232

@@ -40,7 +40,6 @@ pub(crate) struct MatchCheckCtx<'p> {
4040
module: ModuleId,
4141
body: DefWithBodyId,
4242
pub(crate) db: &'p dyn HirDatabase,
43-
pub(crate) pattern_arena: &'p Arena<DeconstructedPat<'p>>,
4443
exhaustive_patterns: bool,
4544
min_exhaustive_patterns: bool,
4645
}
@@ -52,17 +51,12 @@ pub(crate) struct PatData<'p> {
5251
}
5352

5453
impl<'p> MatchCheckCtx<'p> {
55-
pub(crate) fn new(
56-
module: ModuleId,
57-
body: DefWithBodyId,
58-
db: &'p dyn HirDatabase,
59-
pattern_arena: &'p Arena<DeconstructedPat<'p>>,
60-
) -> Self {
54+
pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'p dyn HirDatabase) -> Self {
6155
let def_map = db.crate_def_map(module.krate());
6256
let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns");
6357
let min_exhaustive_patterns =
6458
def_map.is_unstable_feature_enabled("min_exhaustive_patterns");
65-
Self { module, body, db, pattern_arena, exhaustive_patterns, min_exhaustive_patterns }
59+
Self { module, body, db, exhaustive_patterns, min_exhaustive_patterns }
6660
}
6761

6862
fn is_uninhabited(&self, ty: &Ty) -> bool {
@@ -131,15 +125,15 @@ impl<'p> MatchCheckCtx<'p> {
131125
}
132126

133127
pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'p> {
134-
let singleton = |pat| std::slice::from_ref(self.pattern_arena.alloc(pat));
128+
let singleton = |pat| vec![pat];
135129
let ctor;
136-
let fields: &[_];
130+
let fields: Vec<_>;
137131

138132
match pat.kind.as_ref() {
139133
PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat),
140134
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
141135
ctor = Wildcard;
142-
fields = &[];
136+
fields = Vec::new();
143137
}
144138
PatKind::Deref { subpattern } => {
145139
ctor = match pat.ty.kind(Interner) {
@@ -157,7 +151,7 @@ impl<'p> MatchCheckCtx<'p> {
157151
match pat.ty.kind(Interner) {
158152
TyKind::Tuple(_, substs) => {
159153
ctor = Struct;
160-
let mut wilds: SmallVec<[_; 2]> = substs
154+
let mut wilds: Vec<_> = substs
161155
.iter(Interner)
162156
.map(|arg| arg.assert_ty_ref(Interner).clone())
163157
.map(DeconstructedPat::wildcard)
@@ -166,7 +160,7 @@ impl<'p> MatchCheckCtx<'p> {
166160
let idx: u32 = pat.field.into_raw().into();
167161
wilds[idx as usize] = self.lower_pat(&pat.pattern);
168162
}
169-
fields = self.pattern_arena.alloc_extend(wilds)
163+
fields = wilds
170164
}
171165
TyKind::Adt(adt, substs) if is_box(self.db, adt.0) => {
172166
// The only legal patterns of type `Box` (outside `std`) are `_` and box
@@ -216,33 +210,29 @@ impl<'p> MatchCheckCtx<'p> {
216210
field_id_to_id[field_idx as usize] = Some(i);
217211
ty
218212
});
219-
let mut wilds: SmallVec<[_; 2]> =
220-
tys.map(DeconstructedPat::wildcard).collect();
213+
let mut wilds: Vec<_> = tys.map(DeconstructedPat::wildcard).collect();
221214
for pat in subpatterns {
222215
let field_idx: u32 = pat.field.into_raw().into();
223216
if let Some(i) = field_id_to_id[field_idx as usize] {
224217
wilds[i] = self.lower_pat(&pat.pattern);
225218
}
226219
}
227-
fields = self.pattern_arena.alloc_extend(wilds);
220+
fields = wilds;
228221
}
229222
_ => {
230223
never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
231224
ctor = Wildcard;
232-
fields = &[];
225+
fields = Vec::new();
233226
}
234227
}
235228
}
236229
&PatKind::LiteralBool { value } => {
237230
ctor = Bool(value);
238-
fields = &[];
231+
fields = Vec::new();
239232
}
240233
PatKind::Or { pats } => {
241234
ctor = Or;
242-
// Collect here because `Arena::alloc_extend` panics on reentrancy.
243-
let subpats: SmallVec<[_; 2]> =
244-
pats.iter().map(|pat| self.lower_pat(pat)).collect();
245-
fields = self.pattern_arena.alloc_extend(subpats);
235+
fields = pats.iter().map(|pat| self.lower_pat(pat)).collect();
246236
}
247237
}
248238
let data = PatData { db: self.db };
@@ -307,7 +297,7 @@ impl<'p> MatchCheckCtx<'p> {
307297
}
308298

309299
impl<'p> TypeCx for MatchCheckCtx<'p> {
310-
type Error = Void;
300+
type Error = ();
311301
type Ty = Ty;
312302
type VariantIdx = EnumVariantId;
313303
type StrLit = Void;
@@ -463,7 +453,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
463453

464454
fn write_variant_name(
465455
f: &mut fmt::Formatter<'_>,
466-
pat: &rustc_pattern_analysis::pat::DeconstructedPat<'_, Self>,
456+
pat: &rustc_pattern_analysis::pat::DeconstructedPat<Self>,
467457
) -> fmt::Result {
468458
let variant =
469459
pat.ty().as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(pat.ctor(), adt));
@@ -485,8 +475,8 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
485475
Ok(())
486476
}
487477

488-
fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
489-
panic!("{}", fmt)
478+
fn bug(&self, fmt: fmt::Arguments<'_>) {
479+
debug!("{}", fmt)
490480
}
491481
}
492482

crates/ide-diagnostics/src/handlers/missing_match_arms.rs

+18
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,24 @@ fn main() {
310310
);
311311
}
312312

313+
#[test]
314+
fn mismatched_types_issue_15883() {
315+
// Check we don't panic.
316+
check_diagnostics_no_bails(
317+
r#"
318+
//- minicore: option
319+
fn main() {
320+
match Some((true, false)) {
321+
Some(true) | Some(false) => {}
322+
// ^^^^ error: expected (bool, bool), found bool
323+
// ^^^^^ error: expected (bool, bool), found bool
324+
None => {}
325+
}
326+
}
327+
"#,
328+
);
329+
}
330+
313331
#[test]
314332
fn mismatched_types_in_or_patterns() {
315333
cov_mark::check_count!(validate_match_bailed_out, 2);

0 commit comments

Comments
 (0)