support ref-patterns

This commit is contained in:
Aleksey Kladov 2019-01-13 13:34:57 +03:00
parent 40686722ba
commit 8e554ea5fa
5 changed files with 46 additions and 11 deletions

View File

@ -422,6 +422,9 @@ mod tests {
fn do_check_local_name(code: &str, expected_offset: u32) { fn do_check_local_name(code: &str, expected_offset: u32) {
let (off, code) = extract_offset(code); let (off, code) = extract_offset(code);
let file = SourceFile::parse(&code); let file = SourceFile::parse(&code);
let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
.expect("failed to find a name at the target offset");
let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
@ -431,11 +434,8 @@ mod tests {
scopes: Arc::new(scopes), scopes: Arc::new(scopes),
syntax_mapping: Arc::new(body_hir), syntax_mapping: Arc::new(body_hir),
}; };
let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); let local_name_entry = scopes.resolve_local_name(name_ref).unwrap();
let local_name = local_name_entry.ptr(); let local_name = local_name_entry.ptr();
let expected_name =
find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap();
assert_eq!(local_name.range(), expected_name.syntax().range()); assert_eq!(local_name.range(), expected_name.syntax().range());
} }
@ -470,11 +470,26 @@ mod tests {
fn test_resolve_local_name_shadow() { fn test_resolve_local_name_shadow() {
do_check_local_name( do_check_local_name(
r" r"
fn foo(x: String) { fn foo(x: String) {
let x : &str = &x; let x : &str = &x;
x<|> x<|>
}", }
46, ",
53,
);
}
#[test]
fn ref_patterns_contribute_bindings() {
do_check_local_name(
r"
fn foo() {
if let Some(&from) = bar() {
from<|>;
}
}
",
53,
); );
} }
} }

View File

@ -315,15 +315,20 @@ pub enum Pat {
path: Option<Path>, path: Option<Path>,
args: Vec<PatId>, args: Vec<PatId>,
}, },
Ref {
pat: PatId,
mutability: Mutability,
},
} }
impl Pat { impl Pat {
pub fn walk_child_pats(&self, f: impl FnMut(PatId)) { pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
match self { match self {
Pat::Missing | Pat::Bind { .. } => {} Pat::Missing | Pat::Bind { .. } => {}
Pat::TupleStruct { args, .. } => { Pat::TupleStruct { args, .. } => {
args.iter().map(|pat| *pat).for_each(f); args.iter().map(|pat| *pat).for_each(f);
} }
Pat::Ref { pat, .. } => f(*pat),
} }
} }
} }
@ -684,6 +689,11 @@ impl ExprCollector {
let args = p.args().map(|p| self.collect_pat(p)).collect(); let args = p.args().map(|p| self.collect_pat(p)).collect();
self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr) self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr)
} }
ast::PatKind::RefPat(p) => {
let pat = self.collect_pat_opt(p.pat());
let mutability = Mutability::from_mutable(p.is_mut());
self.alloc_pat(Pat::Ref { pat, mutability }, syntax_ptr)
}
_ => { _ => {
// TODO // TODO
self.alloc_pat(Pat::Missing, syntax_ptr) self.alloc_pat(Pat::Missing, syntax_ptr)

View File

@ -348,6 +348,12 @@ impl UseTreeList {
} }
} }
impl RefPat {
pub fn is_mut(&self) -> bool {
self.syntax().children().any(|n| n.kind() == MUT_KW)
}
}
fn child_opt<P: AstNode, C: AstNode>(parent: &P) -> Option<&C> { fn child_opt<P: AstNode, C: AstNode>(parent: &P) -> Option<&C> {
children(parent).next() children(parent).next()
} }

View File

@ -2456,7 +2456,11 @@ impl AstNode for RefPat {
} }
impl RefPat {} impl RefPat {
pub fn pat(&self) -> Option<&Pat> {
super::child_opt(self)
}
}
// ReferenceType // ReferenceType
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]

View File

@ -462,7 +462,7 @@ Grammar(
], ],
), ),
"RefPat": (), "RefPat": ( options: [ "Pat" ]),
"BindPat": ( traits: ["NameOwner"] ), "BindPat": ( traits: ["NameOwner"] ),
"PlaceholderPat": (), "PlaceholderPat": (),
"PathPat": (), "PathPat": (),