Skip to content

Commit 4899ac8

Browse files
committed
Correct binding pattern's type; handle invalid records.
1 parent 3088ca0 commit 4899ac8

File tree

1 file changed

+55
-5
lines changed

1 file changed

+55
-5
lines changed

crates/hir_ty/src/diagnostics/match_check.rs

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub(crate) type PatId = Idx<Pat>;
2424
pub(crate) enum PatternError {
2525
Unimplemented,
2626
UnresolvedVariant,
27+
MissingField,
2728
}
2829

2930
#[derive(Clone, Debug, PartialEq)]
@@ -105,7 +106,7 @@ impl<'a> PatCtxt<'a> {
105106
}
106107

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

111112
let kind = match self.body[pat] {
@@ -127,6 +128,9 @@ impl<'a> PatCtxt<'a> {
127128
}
128129

129130
hir_def::expr::Pat::Bind { subpat, .. } => {
131+
if let TyKind::Ref(.., rty) = ty.kind(&Interner) {
132+
ty = rty;
133+
}
130134
PatKind::Binding { subpattern: self.lower_opt_pattern(subpat) }
131135
}
132136

@@ -140,13 +144,21 @@ impl<'a> PatCtxt<'a> {
140144
let variant_data = variant.unwrap().variant_data(self.db.upcast());
141145
let subpatterns = args
142146
.iter()
143-
.map(|field| FieldPat {
147+
.map(|field| {
144148
// XXX(iDawer): field lookup is inefficient
145-
field: variant_data.field(&field.name).unwrap(),
146-
pattern: self.lower_pattern(field.pat),
149+
variant_data.field(&field.name).map(|lfield_id| FieldPat {
150+
field: lfield_id,
151+
pattern: self.lower_pattern(field.pat),
152+
})
147153
})
148154
.collect();
149-
self.lower_variant_or_leaf(pat, ty, subpatterns)
155+
match subpatterns {
156+
Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns),
157+
None => {
158+
self.errors.push(PatternError::MissingField);
159+
PatKind::Wild
160+
}
161+
}
150162
}
151163
hir_def::expr::Pat::TupleStruct { .. } | hir_def::expr::Pat::Record { .. } => {
152164
self.errors.push(PatternError::UnresolvedVariant);
@@ -1090,6 +1102,31 @@ fn main() {
10901102
);
10911103
}
10921104

1105+
#[test]
1106+
fn binding_ref_has_correct_type() {
1107+
// Asserts `PatKind::Binding(ref _x): bool`, not &bool.
1108+
// If that's not true match checking will panic with "incompatible constructors"
1109+
// FIXME: make facilities to test this directly like `tests::check_infer(..)`
1110+
check_diagnostics(
1111+
r#"
1112+
enum Foo { A }
1113+
fn main() {
1114+
// FIXME: this should not bail out but current behavior is such as the old algorithm.
1115+
// ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
1116+
match Foo::A {
1117+
ref _x => {}
1118+
// ^^^^^^ Internal: match check bailed out
1119+
Foo::A => {}
1120+
}
1121+
match (true,) {
1122+
(ref _x,) => {}
1123+
(true,) => {}
1124+
}
1125+
}
1126+
"#,
1127+
);
1128+
}
1129+
10931130
#[test]
10941131
fn enum_non_exhaustive() {
10951132
check_diagnostics(
@@ -1161,6 +1198,19 @@ fn main() {
11611198
);
11621199
}
11631200

1201+
#[test]
1202+
fn record_struct_no_such_field() {
1203+
check_diagnostics(
1204+
r#"
1205+
struct Foo { }
1206+
fn main(f: Foo) {
1207+
match f { Foo { bar } => () }
1208+
// ^^^^^^^^^^^ Internal: match check bailed out
1209+
}
1210+
"#,
1211+
);
1212+
}
1213+
11641214
mod false_negatives {
11651215
//! The implementation of match checking here is a work in progress. As we roll this out, we
11661216
//! prefer false negatives to false positives (ideally there would be no false positives). This

0 commit comments

Comments
 (0)