mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 11:59:49 +00:00
Implement unlabeled struct field pattern inference
This commit is contained in:
parent
3340807bd2
commit
ac216880f5
4 changed files with 26 additions and 47 deletions
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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 }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue