Correct binding pattern's type; handle invalid records.
This commit is contained in:
parent
3088ca0a53
commit
4899ac8c05
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user