Respect binding mode of a binding pattern for exhaustiveness check

This commit is contained in:
iDawer 2021-12-12 14:24:10 +05:00
parent b17aefb83a
commit a9ad7be748
4 changed files with 32 additions and 5 deletions

View file

@ -11,8 +11,11 @@
pub(crate) mod usefulness;
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;
@ -21,6 +24,7 @@
#[derive(Clone, Debug)]
pub(crate) enum PatternError {
Unimplemented,
UnexpectedType,
UnresolvedVariant,
MissingField,
ExtraFields,
@ -129,9 +133,16 @@ fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat {
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) }
}

View file

@ -100,7 +100,7 @@ enum ExprOrPatId {
/// Binding modes inferred for patterns.
/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum BindingMode {
pub enum BindingMode {
Move,
Ref(Mutability),
}
@ -292,6 +292,7 @@ pub struct InferenceResult {
standard_types: InternedStandardTypes,
/// Stores the types which were implicitly dereferenced in pattern binding modes.
pub pat_adjustments: FxHashMap<PatId, Vec<Adjustment>>,
pub pat_binding_modes: FxHashMap<PatId, BindingMode>,
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
}

View file

@ -204,6 +204,8 @@ pub(super) fn infer_pat(
} else {
BindingMode::convert(*mode)
};
self.result.pat_binding_modes.insert(pat, mode);
let inner_ty = match subpat {
Some(subpat) => self.infer_pat(*subpat, &expected, default_bm),
None => expected,

View file

@ -883,7 +883,20 @@ enum E {Foo, Bar}
match &n { Next(E::Foo | E::Bar) => {} }
match &n { _ | Next(E::Bar) => {} }
};",
);
}
#[test]
fn binding_mode_by_ref() {
check_diagnostics_no_bails(
r"
enum E{ A, B }
fn foo() {
match &E::A {
E::A => {}
x => {}
}
}",
);
}