Correct binding pattern's type; handle invalid records.

This commit is contained in:
Dawer 2021-05-22 12:36:48 +05:00
parent 3088ca0a53
commit 4899ac8c05

View File

@ -24,6 +24,7 @@
pub(crate) enum PatternError { pub(crate) enum PatternError {
Unimplemented, Unimplemented,
UnresolvedVariant, UnresolvedVariant,
MissingField,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -105,7 +106,7 @@ pub(crate) fn lower_pattern(&mut self, pat: hir_def::expr::PatId) -> Pat {
} }
fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat { fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
let ty = &self.infer[pat]; let mut ty = &self.infer[pat];
let variant = self.infer.variant_resolution_for_pat(pat); let variant = self.infer.variant_resolution_for_pat(pat);
let kind = match self.body[pat] { let kind = match self.body[pat] {
@ -127,6 +128,9 @@ fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
} }
hir_def::expr::Pat::Bind { subpat, .. } => { hir_def::expr::Pat::Bind { subpat, .. } => {
if let TyKind::Ref(.., rty) = ty.kind(&Interner) {
ty = rty;
}
PatKind::Binding { subpattern: self.lower_opt_pattern(subpat) } PatKind::Binding { subpattern: self.lower_opt_pattern(subpat) }
} }
@ -140,13 +144,21 @@ fn lower_pattern_unadjusted(&mut self, pat: hir_def::expr::PatId) -> Pat {
let variant_data = variant.unwrap().variant_data(self.db.upcast()); let variant_data = variant.unwrap().variant_data(self.db.upcast());
let subpatterns = args let subpatterns = args
.iter() .iter()
.map(|field| FieldPat { .map(|field| {
// XXX(iDawer): field lookup is inefficient // XXX(iDawer): field lookup is inefficient
field: variant_data.field(&field.name).unwrap(), variant_data.field(&field.name).map(|lfield_id| FieldPat {
field: lfield_id,
pattern: self.lower_pattern(field.pat), pattern: self.lower_pattern(field.pat),
}) })
})
.collect(); .collect();
self.lower_variant_or_leaf(pat, ty, subpatterns) match subpatterns {
Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns),
None => {
self.errors.push(PatternError::MissingField);
PatKind::Wild
}
}
} }
hir_def::expr::Pat::TupleStruct { .. } | hir_def::expr::Pat::Record { .. } => { hir_def::expr::Pat::TupleStruct { .. } | hir_def::expr::Pat::Record { .. } => {
self.errors.push(PatternError::UnresolvedVariant); self.errors.push(PatternError::UnresolvedVariant);
@ -1090,6 +1102,31 @@ fn main() {
); );
} }
#[test]
fn binding_ref_has_correct_type() {
// Asserts `PatKind::Binding(ref _x): bool`, not &bool.
// If that's not true match checking will panic with "incompatible constructors"
// FIXME: make facilities to test this directly like `tests::check_infer(..)`
check_diagnostics(
r#"
enum Foo { A }
fn main() {
// FIXME: this should not bail out but current behavior is such as the old algorithm.
// ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
match Foo::A {
ref _x => {}
// ^^^^^^ Internal: match check bailed out
Foo::A => {}
}
match (true,) {
(ref _x,) => {}
(true,) => {}
}
}
"#,
);
}
#[test] #[test]
fn enum_non_exhaustive() { fn enum_non_exhaustive() {
check_diagnostics( check_diagnostics(
@ -1161,6 +1198,19 @@ fn main() {
); );
} }
#[test]
fn record_struct_no_such_field() {
check_diagnostics(
r#"
struct Foo { }
fn main(f: Foo) {
match f { Foo { bar } => () }
// ^^^^^^^^^^^ Internal: match check bailed out
}
"#,
);
}
mod false_negatives { mod false_negatives {
//! The implementation of match checking here is a work in progress. As we roll this out, we //! The implementation of match checking here is a work in progress. As we roll this out, we
//! prefer false negatives to false positives (ideally there would be no false positives). This //! prefer false negatives to false positives (ideally there would be no false positives). This