Skip to content

Commit a9ad7be

Browse files
committed
Respect binding mode of a binding pattern for exhaustiveness check
1 parent b17aefb commit a9ad7be

File tree

4 files changed

+32
-5
lines changed

4 files changed

+32
-5
lines changed

crates/hir_ty/src/diagnostics/match_check.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ pub(crate) mod deconstruct_pat;
1111
pub(crate) mod usefulness;
1212

1313
use hir_def::{body::Body, expr::PatId, EnumVariantId, LocalFieldId, VariantId};
14+
use stdx::never;
1415

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

1720
use self::pat_util::EnumerateAndAdjustIterator;
1821

@@ -21,6 +24,7 @@ pub(crate) use self::usefulness::MatchArm;
2124
#[derive(Clone, Debug)]
2225
pub(crate) enum PatternError {
2326
Unimplemented,
27+
UnexpectedType,
2428
UnresolvedVariant,
2529
MissingField,
2630
ExtraFields,
@@ -129,9 +133,16 @@ impl<'a> PatCtxt<'a> {
129133
PatKind::Leaf { subpatterns }
130134
}
131135

132-
hir_def::expr::Pat::Bind { subpat, .. } => {
133-
if let TyKind::Ref(.., rty) = ty.kind(Interner) {
134-
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+
_ => (),
135146
}
136147
PatKind::Binding { subpattern: self.lower_opt_pattern(subpat) }
137148
}

crates/hir_ty/src/infer.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl_from!(ExprId, PatId for ExprOrPatId);
100100
/// Binding modes inferred for patterns.
101101
/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
102102
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
103-
enum BindingMode {
103+
pub enum BindingMode {
104104
Move,
105105
Ref(Mutability),
106106
}
@@ -292,6 +292,7 @@ pub struct InferenceResult {
292292
standard_types: InternedStandardTypes,
293293
/// Stores the types which were implicitly dereferenced in pattern binding modes.
294294
pub pat_adjustments: FxHashMap<PatId, Vec<Adjustment>>,
295+
pub pat_binding_modes: FxHashMap<PatId, BindingMode>,
295296
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
296297
}
297298

crates/hir_ty/src/infer/pat.rs

+2
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ impl<'a> InferenceContext<'a> {
204204
} else {
205205
BindingMode::convert(*mode)
206206
};
207+
self.result.pat_binding_modes.insert(pat, mode);
208+
207209
let inner_ty = match subpat {
208210
Some(subpat) => self.infer_pat(*subpat, &expected, default_bm),
209211
None => expected,

crates/ide_diagnostics/src/handlers/missing_match_arms.rs

+13
Original file line numberDiff line numberDiff line change
@@ -883,7 +883,20 @@ static __: () = {
883883
match &n { Next(E::Foo | E::Bar) => {} }
884884
match &n { _ | Next(E::Bar) => {} }
885885
};",
886+
);
887+
}
886888

889+
#[test]
890+
fn binding_mode_by_ref() {
891+
check_diagnostics_no_bails(
892+
r"
893+
enum E{ A, B }
894+
fn foo() {
895+
match &E::A {
896+
E::A => {}
897+
x => {}
898+
}
899+
}",
887900
);
888901
}
889902

0 commit comments

Comments
 (0)