Implement unlabeled struct field pattern inference

This commit is contained in:
Marcus Klaas de Vries 2019-01-17 00:08:10 +01:00 committed by Aleksey Kladov
parent 3340807bd2
commit ac216880f5
4 changed files with 26 additions and 47 deletions

View file

@ -332,7 +332,7 @@ impl_arena_id!(PatId);
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct FieldPat { pub struct FieldPat {
pub(crate) name: Name, pub(crate) name: Name,
pub(crate) pat: Option<PatId>, pub(crate) pat: PatId,
} }
/// Close relative to rustc's hir::PatKind /// Close relative to rustc's hir::PatKind
@ -393,7 +393,7 @@ impl Pat {
total_iter.map(|pat| *pat).for_each(f); total_iter.map(|pat| *pat).for_each(f);
} }
Pat::Struct { args, .. } => { Pat::Struct { args, .. } => {
args.iter().filter_map(|a| a.pat).for_each(f); args.iter().map(|f| f.pat).for_each(f);
} }
} }
} }
@ -821,9 +821,10 @@ impl ExprCollector {
.expect("every struct should have a field list") .expect("every struct should have a field list")
.field_pats() .field_pats()
.into_iter() .into_iter()
.map(|f| FieldPat { .map(|f| {
name: Name::new(f.ident), let name = Name::new(f.ident);
pat: f.pat.as_ref().map(|p| self.collect_pat(p)), let pat = self.collect_pat(&*f.pat);
FieldPat { name, pat }
}) })
.collect(); .collect();

View file

@ -937,19 +937,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}; };
for sub_pat in sub_pats { for sub_pat in sub_pats {
let tyref = fields let matching_field = fields.iter().find(|field| field.name == sub_pat.name);
.iter()
.find(|field| field.name == sub_pat.name)
.map(|field| &field.type_ref);
if let Some(typeref) = tyref { if let Some(field) = matching_field {
let typeref = &field.type_ref;
let sub_ty = Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), typeref); let sub_ty = Ty::from_hir(self.db, &self.module, self.impl_block.as_ref(), typeref);
self.infer_pat(sub_pat.pat, &Expectation::has_type(sub_ty));
if let Some(pat) = sub_pat.pat {
self.infer_pat(pat, &Expectation::has_type(sub_ty));
} else {
// TODO: deal with this case: S { x, y }
}
} }
} }

View file

@ -389,6 +389,11 @@ fn test() {
let S(y, z) = foo; let S(y, z) = foo;
let E::A { x: new_var } = e; let E::A { x: new_var } = e;
match e {
E::A { x } => x,
E::B => 1,
};
} }
"#, "#,
"adt_pattern.txt", "adt_pattern.txt",

View file

@ -664,36 +664,11 @@ impl LiteralExpr {
} }
} }
// STRUCT_PAT@[20; 42)
// PATH@[20; 26)
// PATH_SEGMENT@[20; 26)
// NAME_REF@[20; 26)
// IDENT@[20; 26) "Strukt"
// WHITESPACE@[26; 27)
// FIELD_PAT_LIST@[27; 42)
// L_CURLY@[27; 28)
// WHITESPACE@[28; 29)
// IDENT@[29; 30) "x"
// COLON@[30; 31)
// WHITESPACE@[31; 32)
// BIND_PAT@[32; 33)
// NAME@[32; 33)
// IDENT@[32; 33) "x"
// COMMA@[33; 34)
// WHITESPACE@[34; 35)
// BIND_PAT@[35; 36)
// NAME@[35; 36)
// IDENT@[35; 36) "y"
// COMMA@[36; 37)
// WHITESPACE@[37; 38)
// DOTDOT@[38; 40)
// WHITESPACE@[40; 41)
// R_CURLY@[41; 42)
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct FieldPat { pub struct FieldPat {
pub ident: SmolStr, pub ident: SmolStr,
pub pat: Option<TreeArc<Pat>>, // FIXME: could we use a regular reference?
pub pat: TreeArc<Pat>,
} }
impl FieldPatList { impl FieldPatList {
@ -704,12 +679,17 @@ impl FieldPatList {
let mut pats = Vec::new(); let mut pats = Vec::new();
while let Some(node) = child_iter.next() { while let Some(node) = child_iter.next() {
if node.kind() != IDENT { let kind = node.kind();
if kind != IDENT && kind != BIND_PAT {
continue; continue;
} }
let ident = node.leaf_text().unwrap().clone(); let ident = if let Some(text) = node.leaf_text() {
let mut pat = None; text.clone()
} else {
SmolStr::new(node.text().to_string())
};
let mut pat = Pat::cast(node).map(AstNode::to_owned);
// get pat // get pat
while let Some(node) = child_iter.next() { while let Some(node) = child_iter.next() {
@ -724,7 +704,7 @@ impl FieldPatList {
let field_pat = FieldPat { let field_pat = FieldPat {
ident: ident, ident: ident,
pat: pat, pat: pat.unwrap(),
}; };
pats.push(field_pat); pats.push(field_pat);
} }