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) { fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
match &body[pat] { match &body[pat] {
Pat::Bind { name, .. } => self.scopes[scope].entries.push(ScopeEntry { Pat::Bind { name, .. } => {
name: name.clone(), // bind can have a subpattern, but it's actually not allowed
pat, // 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)), p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
} }
} }

View File

@ -398,7 +398,7 @@ pub enum Pat {
Bind { Bind {
mode: BindingAnnotation, mode: BindingAnnotation,
name: Name, name: Name,
sub_pat: Option<PatId>, subpat: Option<PatId>,
}, },
TupleStruct { TupleStruct {
path: Option<Path>, path: Option<Path>,
@ -413,12 +413,10 @@ pub enum Pat {
impl Pat { impl Pat {
pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
match self { match self {
Pat::Range { .. } Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {}
| Pat::Lit(..) Pat::Bind { subpat, .. } => {
| Pat::Path(..) subpat.iter().map(|pat| *pat).for_each(f);
| Pat::Wild }
| Pat::Missing
| Pat::Bind { .. } => {}
Pat::Tuple(args) | Pat::TupleStruct { args, .. } => { Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
args.iter().map(|pat| *pat).for_each(f); args.iter().map(|pat| *pat).for_each(f);
} }
@ -833,11 +831,11 @@ impl ExprCollector {
.map(|nr| nr.as_name()) .map(|nr| nr.as_name())
.unwrap_or_else(Name::missing); .unwrap_or_else(Name::missing);
let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); 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 { Pat::Bind {
name, name,
mode: annotation, mode: annotation,
sub_pat, subpat,
} }
} }
ast::PatKind::TupleStructPat(p) => { ast::PatKind::TupleStructPat(p) => {
@ -928,7 +926,7 @@ pub(crate) fn collect_fn_body_syntax(node: &ast::FnDef) -> BodySyntaxMapping {
Pat::Bind { Pat::Bind {
name: Name::self_param(), name: Name::self_param(),
mode: BindingAnnotation::Unannotated, mode: BindingAnnotation::Unannotated,
sub_pat: None, subpat: None,
}, },
self_param, 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) { let (ty, fields) = if let Some(x) = self.resolve_fields(path) {
x x
} else { } else {
return Ty::Unknown; return Ty::Unknown;
}; };
if fields.len() != sub_pats.len() { if fields.len() != subpats.len() {
return Ty::Unknown; 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); 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 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) { let (ty, fields) = if let Some(x) = self.resolve_fields(path) {
x x
} else { } else {
return Ty::Unknown; return Ty::Unknown;
}; };
for sub_pat in sub_pats { for subpat in subpats {
let matching_field = fields.iter().find(|field| field.name == sub_pat.name); let matching_field = fields.iter().find(|field| field.name == subpat.name);
if let Some(field) = matching_field { if let Some(field) = matching_field {
let typeref = &field.type_ref; let typeref = &field.type_ref;
let sub_ty = self.make_ty(typeref); 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 { Pat::TupleStruct {
path: ref p, path: ref p,
args: ref sub_pats, args: ref subpats,
} => self.infer_tuple_struct(p.as_ref(), sub_pats), } => self.infer_tuple_struct(p.as_ref(), subpats),
Pat::Struct { Pat::Struct {
path: ref p, path: ref p,
args: ref fields, args: ref fields,
@ -995,12 +995,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Pat::Bind { Pat::Bind {
mode, mode,
name: _name, 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) self.infer_pat(*subpat, expected)
} else { } 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 { match mode {

View File

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

View File

@ -1,4 +1,4 @@
[68; 221) '{ ... }; }': () [68; 262) '{ ... d; }': ()
[78; 79) 'e': E [78; 79) 'e': E
[82; 95) 'E::A { x: 3 }': E [82; 95) 'E::A { x: 3 }': E
[92; 93) '3': usize [92; 93) '3': usize
@ -16,3 +16,7 @@
[191; 192) 'x': usize [191; 192) 'x': usize
[202; 206) 'E::B': E [202; 206) 'E::B': E
[210; 211) '1': usize [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 [9; 10) 'x': &i32
[18; 259) '{ ...c }; }': () [18; 369) '{ ...o_x; }': ()
[28; 29) 'y': &i32 [28; 29) 'y': &i32
[32; 33) 'x': &i32 [32; 33) 'x': &i32
[43; 45) '&z': &i32 [43; 45) '&z': &i32
@ -37,3 +37,11 @@
[246; 251) 'a + b': u64 [246; 251) 'a + b': u64
[250; 251) 'b': u64 [250; 251) 'b': u64
[253; 254) 'c': i32 [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