Skip to content

Commit 48d6cef

Browse files
bors[bot]iDawer
andauthored
Merge #10484
10484: internal: Update match checking algorithm r=lnicola a=iDawer Sync match checking algorithm with rust-lang/rust f31622a50 2021-11-12 (rust-lang/rust#90813) This update brings huge simplification to the match checking and introduces an easy to use machinery for pattern destructuring and also: 1. Add a function to do post-inference normalization `hir_ty::infer::normalize(...)`. 2. Store binding modes in `InferenceResult`. Todo: - [x] Rebase & test (#10484 (comment)) Co-authored-by: Dawer <7803845+iDawer@users.noreply.github.com> Co-authored-by: iDawer <ilnur.iskhakov.oss@outlook.com>
2 parents 2ca3834 + a9ad7be commit 48d6cef

File tree

9 files changed

+699
-886
lines changed

9 files changed

+699
-886
lines changed

Cargo.lock

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

crates/hir_ty/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ chalk-ir = "0.75"
2323
chalk-recursive = { version = "0.75", default-features = false }
2424
la-arena = { version = "0.3.0", path = "../../lib/arena" }
2525
once_cell = { version = "1.5.0" }
26+
typed-arena = "2.0.1"
2627

2728
stdx = { path = "../stdx", version = "0.0.0" }
2829
hir_def = { path = "../hir_def", version = "0.0.0" }

crates/hir_ty/src/diagnostics/expr.rs

+22-28
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! through the body using inference results: mismatched arg counts, missing
33
//! fields, etc.
44
5-
use std::{cell::RefCell, sync::Arc};
5+
use std::sync::Arc;
66

77
use hir_def::{
88
expr::Statement, path::path, resolver::HasResolver, type_ref::Mutability, AssocItemId,
@@ -11,12 +11,14 @@ use hir_def::{
1111
use hir_expand::name;
1212
use itertools::Either;
1313
use rustc_hash::FxHashSet;
14+
use typed_arena::Arena;
1415

1516
use crate::{
1617
db::HirDatabase,
1718
diagnostics::match_check::{
1819
self,
19-
usefulness::{compute_match_usefulness, expand_pattern, MatchCheckCtx, PatternArena},
20+
deconstruct_pat::DeconstructedPat,
21+
usefulness::{compute_match_usefulness, MatchCheckCtx},
2022
},
2123
AdtId, InferenceResult, Interner, Ty, TyExt, TyKind,
2224
};
@@ -275,15 +277,20 @@ impl ExprValidator {
275277
) {
276278
let body = db.body(self.owner);
277279

278-
let match_expr_ty = if infer.type_of_expr[match_expr].is_unknown() {
280+
let match_expr_ty = &infer[match_expr];
281+
if match_expr_ty.is_unknown() {
279282
return;
280-
} else {
281-
&infer.type_of_expr[match_expr]
282-
};
283+
}
283284

284-
let pattern_arena = RefCell::new(PatternArena::new());
285+
let pattern_arena = Arena::new();
286+
let cx = MatchCheckCtx {
287+
module: self.owner.module(db.upcast()),
288+
body: self.owner,
289+
db,
290+
pattern_arena: &pattern_arena,
291+
};
285292

286-
let mut m_arms = Vec::new();
293+
let mut m_arms = Vec::with_capacity(arms.len());
287294
let mut has_lowering_errors = false;
288295
for arm in arms {
289296
if let Some(pat_ty) = infer.type_of_pat.get(arm.pat) {
@@ -308,13 +315,7 @@ impl ExprValidator {
308315
// check the usefulness of each pattern as we added it
309316
// to the matrix here.
310317
let m_arm = match_check::MatchArm {
311-
pat: self.lower_pattern(
312-
arm.pat,
313-
&mut pattern_arena.borrow_mut(),
314-
db,
315-
&body,
316-
&mut has_lowering_errors,
317-
),
318+
pat: self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors),
318319
has_guard: arm.guard.is_some(),
319320
};
320321
m_arms.push(m_arm);
@@ -332,17 +333,10 @@ impl ExprValidator {
332333
return;
333334
}
334335

335-
let cx = MatchCheckCtx {
336-
module: self.owner.module(db.upcast()),
337-
match_expr,
338-
infer: &infer,
339-
db,
340-
pattern_arena: &pattern_arena,
341-
};
342-
let report = compute_match_usefulness(&cx, &m_arms);
336+
let report = compute_match_usefulness(&cx, &m_arms, match_expr_ty);
343337

344338
// FIXME Report unreacheble arms
345-
// https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200-L201
339+
// https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200
346340

347341
let witnesses = report.non_exhaustiveness_witnesses;
348342
// FIXME Report witnesses
@@ -352,17 +346,17 @@ impl ExprValidator {
352346
}
353347
}
354348

355-
fn lower_pattern(
349+
fn lower_pattern<'p>(
356350
&self,
351+
cx: &MatchCheckCtx<'_, 'p>,
357352
pat: PatId,
358-
pattern_arena: &mut PatternArena,
359353
db: &dyn HirDatabase,
360354
body: &Body,
361355
have_errors: &mut bool,
362-
) -> match_check::PatId {
356+
) -> &'p DeconstructedPat<'p> {
363357
let mut patcx = match_check::PatCtxt::new(db, &self.infer, body);
364358
let pattern = patcx.lower_pattern(pat);
365-
let pattern = pattern_arena.alloc(expand_pattern(pattern));
359+
let pattern = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern));
366360
if !patcx.errors.is_empty() {
367361
*have_errors = true;
368362
}

crates/hir_ty/src/diagnostics/match_check.rs

+24-22
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,26 @@
55
//!
66
//! It is modeled on the rustc module `rustc_mir_build::thir::pattern`.
77
8-
mod deconstruct_pat;
98
mod pat_util;
109

10+
pub(crate) mod deconstruct_pat;
1111
pub(crate) mod usefulness;
1212

13-
use hir_def::{body::Body, EnumVariantId, LocalFieldId, VariantId};
14-
use la_arena::Idx;
13+
use hir_def::{body::Body, expr::PatId, EnumVariantId, LocalFieldId, VariantId};
14+
use stdx::never;
1515

16-
use crate::{db::HirDatabase, InferenceResult, Interner, Substitution, Ty, TyKind};
16+
use crate::{
17+
db::HirDatabase, infer::BindingMode, InferenceResult, Interner, Substitution, Ty, TyKind,
18+
};
1719

1820
use self::pat_util::EnumerateAndAdjustIterator;
1921

2022
pub(crate) use self::usefulness::MatchArm;
2123

22-
pub(crate) type PatId = Idx<Pat>;
23-
2424
#[derive(Clone, Debug)]
2525
pub(crate) enum PatternError {
2626
Unimplemented,
27+
UnexpectedType,
2728
UnresolvedVariant,
2829
MissingField,
2930
ExtraFields,
@@ -41,12 +42,6 @@ pub(crate) struct Pat {
4142
pub(crate) kind: Box<PatKind>,
4243
}
4344

44-
impl Pat {
45-
pub(crate) fn wildcard_from_ty(ty: Ty) -> Self {
46-
Pat { ty, kind: Box::new(PatKind::Wild) }
47-
}
48-
}
49-
5045
/// Close relative to `rustc_mir_build::thir::pattern::PatKind`
5146
#[derive(Clone, Debug, PartialEq)]
5247
pub(crate) enum PatKind {
@@ -100,7 +95,7 @@ impl<'a> PatCtxt<'a> {
10095
Self { db, infer, body, errors: Vec::new() }
10196
}
10297

103-
pub(crate) fn lower_pattern(&mut self, pat: hir_def::expr::PatId) -> Pat {
98+
pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat {
10499
// XXX(iDawer): Collecting pattern adjustments feels imprecise to me.
105100
// When lowering of & and box patterns are implemented this should be tested
106101
// in a manner of `match_ergonomics_issue_9095` test.
@@ -116,7 +111,7 @@ impl<'a> PatCtxt<'a> {
116111
)
117112
}
118113

119-
fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
114+
fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat {
120115
let mut ty = &self.infer[pat];
121116
let variant = self.infer.variant_resolution_for_pat(pat);
122117

@@ -138,9 +133,16 @@ impl<'a> PatCtxt<'a> {
138133
PatKind::Leaf { subpatterns }
139134
}
140135

141-
hir_def::expr::Pat::Bind { subpat, .. } => {
142-
if let TyKind::Ref(.., rty) = ty.kind(Interner) {
143-
ty = rty;
136+
hir_def::expr::Pat::Bind { ref name, subpat, .. } => {
137+
let bm = self.infer.pat_binding_modes[&pat];
138+
match (bm, ty.kind(Interner)) {
139+
(BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty,
140+
(BindingMode::Ref(_), _) => {
141+
never!("`ref {}` has wrong type {:?}", name, ty);
142+
self.errors.push(PatternError::UnexpectedType);
143+
return Pat { ty: ty.clone(), kind: PatKind::Wild.into() };
144+
}
145+
_ => (),
144146
}
145147
PatKind::Binding { subpattern: self.lower_opt_pattern(subpat) }
146148
}
@@ -189,7 +191,7 @@ impl<'a> PatCtxt<'a> {
189191

190192
fn lower_tuple_subpats(
191193
&mut self,
192-
pats: &[hir_def::expr::PatId],
194+
pats: &[PatId],
193195
expected_len: usize,
194196
ellipsis: Option<usize>,
195197
) -> Vec<FieldPat> {
@@ -207,17 +209,17 @@ impl<'a> PatCtxt<'a> {
207209
.collect()
208210
}
209211

210-
fn lower_patterns(&mut self, pats: &[hir_def::expr::PatId]) -> Vec<Pat> {
212+
fn lower_patterns(&mut self, pats: &[PatId]) -> Vec<Pat> {
211213
pats.iter().map(|&p| self.lower_pattern(p)).collect()
212214
}
213215

214-
fn lower_opt_pattern(&mut self, pat: Option<hir_def::expr::PatId>) -> Option<Pat> {
216+
fn lower_opt_pattern(&mut self, pat: Option<PatId>) -> Option<Pat> {
215217
pat.map(|p| self.lower_pattern(p))
216218
}
217219

218220
fn lower_variant_or_leaf(
219221
&mut self,
220-
pat: hir_def::expr::PatId,
222+
pat: PatId,
221223
ty: &Ty,
222224
subpatterns: Vec<FieldPat>,
223225
) -> PatKind {
@@ -244,7 +246,7 @@ impl<'a> PatCtxt<'a> {
244246
kind
245247
}
246248

247-
fn lower_path(&mut self, pat: hir_def::expr::PatId, _path: &hir_def::path::Path) -> Pat {
249+
fn lower_path(&mut self, pat: PatId, _path: &hir_def::path::Path) -> Pat {
248250
let ty = &self.infer[pat];
249251

250252
let pat_from_kind = |kind| Pat { ty: ty.clone(), kind: Box::new(kind) };

0 commit comments

Comments
 (0)