Fixup annotated bindings

This commit is contained in:
Marcus Klaas de Vries 2019-01-17 13:40:45 +01:00 committed by Aleksey Kladov
parent d48d5b8b6c
commit 44e9a9605b
6 changed files with 54 additions and 30 deletions

View File

@ -88,10 +88,17 @@ impl FnScopes {
fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
match &body[pat] {
Pat::Bind { name, .. } => self.scopes[scope].entries.push(ScopeEntry {
name: name.clone(),
pat,
}),
Pat::Bind { name, .. } => {
// bind can have a subpattern, but it's actually not allowed
// to bind to things in there
let entry = ScopeEntry {
name: name.clone(),
pat,
};
self.scopes[scope].entries.push(entry)
}
// FIXME: isn't every call to add_binding starting an entirely new
// tree walk!?
p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
}
}

View File

@ -398,7 +398,7 @@ pub enum Pat {
Bind {
mode: BindingAnnotation,
name: Name,
sub_pat: Option<PatId>,
subpat: Option<PatId>,
},
TupleStruct {
path: Option<Path>,
@ -413,12 +413,10 @@ pub enum Pat {
impl Pat {
pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
match self {
Pat::Range { .. }
| Pat::Lit(..)
| Pat::Path(..)
| Pat::Wild
| Pat::Missing
| Pat::Bind { .. } => {}
Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {}
Pat::Bind { subpat, .. } => {
subpat.iter().map(|pat| *pat).for_each(f);
}
Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
args.iter().map(|pat| *pat).for_each(f);
}
@ -833,11 +831,11 @@ impl ExprCollector {
.map(|nr| nr.as_name())
.unwrap_or_else(Name::missing);
let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
let sub_pat = bp.pat().map(|subpat| self.collect_pat(subpat));
let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
Pat::Bind {
name,
mode: annotation,
sub_pat,
subpat,
}
}
ast::PatKind::TupleStructPat(p) => {
@ -928,7 +926,7 @@ pub(crate) fn collect_fn_body_syntax(node: &ast::FnDef) -> BodySyntaxMapping {
Pat::Bind {
name: Name::self_param(),
mode: BindingAnnotation::Unannotated,
sub_pat: None,
subpat: None,
},
self_param,
);

View File

@ -904,39 +904,39 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}
}
fn infer_tuple_struct(&mut self, path: Option<&Path>, sub_pats: &[PatId]) -> Ty {
fn infer_tuple_struct(&mut self, path: Option<&Path>, subpats: &[PatId]) -> Ty {
let (ty, fields) = if let Some(x) = self.resolve_fields(path) {
x
} else {
return Ty::Unknown;
};
if fields.len() != sub_pats.len() {
if fields.len() != subpats.len() {
return Ty::Unknown;
}
for (&sub_pat, field) in sub_pats.iter().zip(fields.iter()) {
for (&subpat, field) in subpats.iter().zip(fields.iter()) {
let sub_ty = self.make_ty(&field.type_ref);
self.infer_pat(sub_pat, &Expectation::has_type(sub_ty));
self.infer_pat(subpat, &Expectation::has_type(sub_ty));
}
ty
}
fn infer_struct(&mut self, path: Option<&Path>, sub_pats: &[FieldPat]) -> Ty {
fn infer_struct(&mut self, path: Option<&Path>, subpats: &[FieldPat]) -> Ty {
let (ty, fields) = if let Some(x) = self.resolve_fields(path) {
x
} else {
return Ty::Unknown;
};
for sub_pat in sub_pats {
let matching_field = fields.iter().find(|field| field.name == sub_pat.name);
for subpat in subpats {
let matching_field = fields.iter().find(|field| field.name == subpat.name);
if let Some(field) = matching_field {
let typeref = &field.type_ref;
let sub_ty = self.make_ty(typeref);
self.infer_pat(sub_pat.pat, &Expectation::has_type(sub_ty));
self.infer_pat(subpat.pat, &Expectation::has_type(sub_ty));
}
}
@ -979,8 +979,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}
Pat::TupleStruct {
path: ref p,
args: ref sub_pats,
} => self.infer_tuple_struct(p.as_ref(), sub_pats),
args: ref subpats,
} => self.infer_tuple_struct(p.as_ref(), subpats),
Pat::Struct {
path: ref p,
args: ref fields,
@ -995,12 +995,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Pat::Bind {
mode,
name: _name,
sub_pat,
subpat,
} => {
let subty = if let Some(subpat) = sub_pat {
let subty = if let Some(subpat) = subpat {
self.infer_pat(*subpat, expected)
} else {
Ty::Unknown
let ty = self.new_type_var();
self.unify(&ty, &expected.ty);
let ty = self.resolve_ty_as_possible(ty);
ty
};
match mode {

View File

@ -359,7 +359,7 @@ fn test(x: &str, y: isize) {
}
#[test]
fn infer_simple_pattern() {
fn infer_pattern() {
check_inference(
r#"
fn test(x: &i32) {
@ -381,6 +381,7 @@ fn test(x: &i32) {
let ref ref_to_x = x;
let mut mut_x = x;
let ref mut mut_ref_to_x = x;
let k = mut_ref_to_x;
}
"#,
"pattern.txt",
@ -408,6 +409,9 @@ fn test() {
E::A { x } => x,
E::B => 1,
};
let ref d @ E::A { .. } = e;
d;
}
"#,
"adt_pattern.txt",

View File

@ -1,4 +1,4 @@
[68; 221) '{ ... }; }': ()
[68; 262) '{ ... d; }': ()
[78; 79) 'e': E
[82; 95) 'E::A { x: 3 }': E
[92; 93) '3': usize
@ -16,3 +16,7 @@
[191; 192) 'x': usize
[202; 206) 'E::B': E
[210; 211) '1': usize
[229; 248) 'ref d ...{ .. }': &E
[237; 248) 'E::A { .. }': E
[251; 252) 'e': E
[258; 259) 'd': &E

View File

@ -1,5 +1,5 @@
[9; 10) 'x': &i32
[18; 259) '{ ...c }; }': ()
[18; 369) '{ ...o_x; }': ()
[28; 29) 'y': &i32
[32; 33) 'x': &i32
[43; 45) '&z': &i32
@ -37,3 +37,11 @@
[246; 251) 'a + b': u64
[250; 251) 'b': u64
[253; 254) 'c': i32
[267; 279) 'ref ref_to_x': &&i32
[282; 283) 'x': &i32
[293; 302) 'mut mut_x': &i32
[305; 306) 'x': &i32
[316; 336) 'ref mu...f_to_x': &mut &i32
[339; 340) 'x': &i32
[350; 351) 'k': &mut &i32
[354; 366) 'mut_ref_to_x': &mut &i32