Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs19
-rw-r--r--crates/hir_ty/src/infer.rs3
-rw-r--r--crates/hir_ty/src/infer/pat.rs2
-rw-r--r--crates/ide_diagnostics/src/handlers/missing_match_arms.rs13
4 files changed, 32 insertions, 5 deletions
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index fdf448f5e1..87a8579761 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -11,8 +11,11 @@ pub(crate) mod deconstruct_pat;
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 @@ pub(crate) use self::usefulness::MatchArm;
#[derive(Clone, Debug)]
pub(crate) enum PatternError {
Unimplemented,
+ UnexpectedType,
UnresolvedVariant,
MissingField,
ExtraFields,
@@ -129,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) }
}
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 95d9a6735a..54c3590f04 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -100,7 +100,7 @@ impl_from!(ExprId, PatId for 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>>,
}
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 64e72abf0f..50fd2dd749 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -204,6 +204,8 @@ impl<'a> InferenceContext<'a> {
} 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,
diff --git a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
index 5ef4d2a226..6e2764e59f 100644
--- a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
@@ -883,7 +883,20 @@ static __: () = {
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 => {}
+ }
+}",
);
}