Skip to content

Commit

Permalink
Merge #10484
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
3 people authored Dec 20, 2021
2 parents 2ca3834 + a9ad7be commit 48d6cef
Show file tree
Hide file tree
Showing 9 changed files with 699 additions and 886 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/hir_ty/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ chalk-ir = "0.75"
chalk-recursive = { version = "0.75", default-features = false }
la-arena = { version = "0.3.0", path = "../../lib/arena" }
once_cell = { version = "1.5.0" }
typed-arena = "2.0.1"

stdx = { path = "../stdx", version = "0.0.0" }
hir_def = { path = "../hir_def", version = "0.0.0" }
Expand Down
50 changes: 22 additions & 28 deletions crates/hir_ty/src/diagnostics/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! through the body using inference results: mismatched arg counts, missing
//! fields, etc.
use std::{cell::RefCell, sync::Arc};
use std::sync::Arc;

use hir_def::{
expr::Statement, path::path, resolver::HasResolver, type_ref::Mutability, AssocItemId,
Expand All @@ -11,12 +11,14 @@ use hir_def::{
use hir_expand::name;
use itertools::Either;
use rustc_hash::FxHashSet;
use typed_arena::Arena;

use crate::{
db::HirDatabase,
diagnostics::match_check::{
self,
usefulness::{compute_match_usefulness, expand_pattern, MatchCheckCtx, PatternArena},
deconstruct_pat::DeconstructedPat,
usefulness::{compute_match_usefulness, MatchCheckCtx},
},
AdtId, InferenceResult, Interner, Ty, TyExt, TyKind,
};
Expand Down Expand Up @@ -275,15 +277,20 @@ impl ExprValidator {
) {
let body = db.body(self.owner);

let match_expr_ty = if infer.type_of_expr[match_expr].is_unknown() {
let match_expr_ty = &infer[match_expr];
if match_expr_ty.is_unknown() {
return;
} else {
&infer.type_of_expr[match_expr]
};
}

let pattern_arena = RefCell::new(PatternArena::new());
let pattern_arena = Arena::new();
let cx = MatchCheckCtx {
module: self.owner.module(db.upcast()),
body: self.owner,
db,
pattern_arena: &pattern_arena,
};

let mut m_arms = Vec::new();
let mut m_arms = Vec::with_capacity(arms.len());
let mut has_lowering_errors = false;
for arm in arms {
if let Some(pat_ty) = infer.type_of_pat.get(arm.pat) {
Expand All @@ -308,13 +315,7 @@ impl ExprValidator {
// check the usefulness of each pattern as we added it
// to the matrix here.
let m_arm = match_check::MatchArm {
pat: self.lower_pattern(
arm.pat,
&mut pattern_arena.borrow_mut(),
db,
&body,
&mut has_lowering_errors,
),
pat: self.lower_pattern(&cx, arm.pat, db, &body, &mut has_lowering_errors),
has_guard: arm.guard.is_some(),
};
m_arms.push(m_arm);
Expand All @@ -332,17 +333,10 @@ impl ExprValidator {
return;
}

let cx = MatchCheckCtx {
module: self.owner.module(db.upcast()),
match_expr,
infer: &infer,
db,
pattern_arena: &pattern_arena,
};
let report = compute_match_usefulness(&cx, &m_arms);
let report = compute_match_usefulness(&cx, &m_arms, match_expr_ty);

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

let witnesses = report.non_exhaustiveness_witnesses;
// FIXME Report witnesses
Expand All @@ -352,17 +346,17 @@ impl ExprValidator {
}
}

fn lower_pattern(
fn lower_pattern<'p>(
&self,
cx: &MatchCheckCtx<'_, 'p>,
pat: PatId,
pattern_arena: &mut PatternArena,
db: &dyn HirDatabase,
body: &Body,
have_errors: &mut bool,
) -> match_check::PatId {
) -> &'p DeconstructedPat<'p> {
let mut patcx = match_check::PatCtxt::new(db, &self.infer, body);
let pattern = patcx.lower_pattern(pat);
let pattern = pattern_arena.alloc(expand_pattern(pattern));
let pattern = cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, &pattern));
if !patcx.errors.is_empty() {
*have_errors = true;
}
Expand Down
46 changes: 24 additions & 22 deletions crates/hir_ty/src/diagnostics/match_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,26 @@
//!
//! It is modeled on the rustc module `rustc_mir_build::thir::pattern`.
mod deconstruct_pat;
mod pat_util;

pub(crate) mod deconstruct_pat;
pub(crate) mod usefulness;

use hir_def::{body::Body, EnumVariantId, LocalFieldId, VariantId};
use la_arena::Idx;
use hir_def::{body::Body, expr::PatId, EnumVariantId, LocalFieldId, VariantId};
use stdx::never;

use crate::{db::HirDatabase, InferenceResult, Interner, Substitution, Ty, TyKind};
use crate::{
db::HirDatabase, infer::BindingMode, InferenceResult, Interner, Substitution, Ty, TyKind,
};

use self::pat_util::EnumerateAndAdjustIterator;

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

pub(crate) type PatId = Idx<Pat>;

#[derive(Clone, Debug)]
pub(crate) enum PatternError {
Unimplemented,
UnexpectedType,
UnresolvedVariant,
MissingField,
ExtraFields,
Expand All @@ -41,12 +42,6 @@ pub(crate) struct Pat {
pub(crate) kind: Box<PatKind>,
}

impl Pat {
pub(crate) fn wildcard_from_ty(ty: Ty) -> Self {
Pat { ty, kind: Box::new(PatKind::Wild) }
}
}

/// Close relative to `rustc_mir_build::thir::pattern::PatKind`
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum PatKind {
Expand Down Expand Up @@ -100,7 +95,7 @@ impl<'a> PatCtxt<'a> {
Self { db, infer, body, errors: Vec::new() }
}

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

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

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

hir_def::expr::Pat::Bind { subpat, .. } => {
if let TyKind::Ref(.., rty) = ty.kind(Interner) {
ty = rty;
hir_def::expr::Pat::Bind { ref name, subpat, .. } => {
let bm = self.infer.pat_binding_modes[&pat];
match (bm, ty.kind(Interner)) {
(BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty,
(BindingMode::Ref(_), _) => {
never!("`ref {}` has wrong type {:?}", name, ty);
self.errors.push(PatternError::UnexpectedType);
return Pat { ty: ty.clone(), kind: PatKind::Wild.into() };
}
_ => (),
}
PatKind::Binding { subpattern: self.lower_opt_pattern(subpat) }
}
Expand Down Expand Up @@ -189,7 +191,7 @@ impl<'a> PatCtxt<'a> {

fn lower_tuple_subpats(
&mut self,
pats: &[hir_def::expr::PatId],
pats: &[PatId],
expected_len: usize,
ellipsis: Option<usize>,
) -> Vec<FieldPat> {
Expand All @@ -207,17 +209,17 @@ impl<'a> PatCtxt<'a> {
.collect()
}

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

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

fn lower_variant_or_leaf(
&mut self,
pat: hir_def::expr::PatId,
pat: PatId,
ty: &Ty,
subpatterns: Vec<FieldPat>,
) -> PatKind {
Expand All @@ -244,7 +246,7 @@ impl<'a> PatCtxt<'a> {
kind
}

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

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

0 comments on commit 48d6cef

Please sign in to comment.