From afaa26636e4391ebacfc09e9c994c11bab58b834 Mon Sep 17 00:00:00 2001 From: Marcus Klaas de Vries Date: Tue, 15 Jan 2019 15:24:04 +0100 Subject: Add additional pattern variants --- .../ra_hir/src/code_model_impl/function/scope.rs | 11 ++++ crates/ra_hir/src/expr.rs | 67 +++++++++++++++++----- crates/ra_hir/src/ty.rs | 5 ++ crates/ra_hir/src/ty/tests.rs | 15 +++++ crates/ra_syntax/src/ast/generated.rs | 12 +++- crates/ra_syntax/src/grammar.ron | 4 +- 6 files changed, 97 insertions(+), 17 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/code_model_impl/function/scope.rs b/crates/ra_hir/src/code_model_impl/function/scope.rs index afca1e9f8..c551e445a 100644 --- a/crates/ra_hir/src/code_model_impl/function/scope.rs +++ b/crates/ra_hir/src/code_model_impl/function/scope.rs @@ -47,9 +47,11 @@ impl FnScopes { compute_expr_scopes(body.body_expr(), &body, &mut scopes, root); scopes } + pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { &self.scopes[scope].entries } + pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator + 'a { generate(self.scope_for(expr), move |&scope| { self.scopes[scope].parent @@ -76,12 +78,14 @@ impl FnScopes { entries: vec![], }) } + fn new_scope(&mut self, parent: ScopeId) -> ScopeId { self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![], }) } + fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { match &body[pat] { Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry { @@ -91,15 +95,18 @@ impl FnScopes { p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)), } } + fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) { let body = Arc::clone(&self.body); params .into_iter() .for_each(|pat| self.add_bindings(&body, scope, *pat)); } + fn set_scope(&mut self, node: ExprId, scope: ScopeId) { self.scope_for.insert(node, scope); } + fn scope_for(&self, expr: ExprId) -> Option { self.scope_for.get(&expr).map(|&scope| scope) } @@ -121,6 +128,7 @@ impl ScopeEntryWithSyntax { pub fn name(&self) -> &Name { &self.name } + pub fn ptr(&self) -> LocalSyntaxPtr { self.ptr } @@ -132,6 +140,7 @@ impl ScopesWithSyntaxMapping { self.scopes.scopes[scope].parent }) } + pub fn scope_chain_for_offset<'a>( &'a self, offset: TextUnit, @@ -152,6 +161,7 @@ impl ScopesWithSyntaxMapping { generate(scope, move |&scope| self.scopes.scopes[scope].parent) } + // XXX: during completion, cursor might be outside of any particular // expression. Try to figure out the correct scope... fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { @@ -225,6 +235,7 @@ impl ScopeEntry { pub fn name(&self) -> &Name { &self.name } + pub fn pat(&self) -> PatId { self.pat } diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 6e98ebc69..8f7e75309 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -329,9 +329,25 @@ impl Expr { pub struct PatId(RawId); impl_arena_id!(PatId); +/// Close relative to rustc's hir::PatKind #[derive(Debug, Clone, Eq, PartialEq)] pub enum Pat { - Missing, + Missing, // do we need this? + Wild, + Tuple(Vec), + Struct, // TODO + Range { + start: ExprId, + end: ExprId, + }, + Box(PatId), + Slice { + prefix: Vec, + rest: Option, + suffix: Vec, + }, + Path(Path), + Lit(ExprId), Bind { name: Name, }, @@ -348,11 +364,25 @@ pub enum Pat { impl Pat { pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { match self { - Pat::Missing | Pat::Bind { .. } => {} - Pat::TupleStruct { args, .. } => { + Pat::Range { .. } + | Pat::Lit(..) + | Pat::Path(..) + | Pat::Wild + | Pat::Missing + | Pat::Bind { .. } => {} + Pat::Tuple(args) | Pat::TupleStruct { args, .. } => { args.iter().map(|pat| *pat).for_each(f); } - Pat::Ref { pat, .. } => f(*pat), + Pat::Ref { pat, .. } | Pat::Box(pat) => f(*pat), + Pat::Slice { + prefix, + rest, + suffix, + } => { + let total_iter = prefix.iter().chain(rest.iter()).chain(suffix.iter()); + total_iter.map(|pat| *pat).for_each(f); + } + Pat::Struct { .. } => {} // TODO } } } @@ -745,30 +775,41 @@ impl ExprCollector { } fn collect_pat(&mut self, pat: &ast::Pat) -> PatId { - let syntax_ptr = LocalSyntaxPtr::new(pat.syntax()); - match pat.kind() { + let pattern = match pat.kind() { ast::PatKind::BindPat(bp) => { let name = bp .name() .map(|nr| nr.as_name()) .unwrap_or_else(Name::missing); - self.alloc_pat(Pat::Bind { name }, syntax_ptr) + Pat::Bind { name } } ast::PatKind::TupleStructPat(p) => { let path = p.path().and_then(Path::from_ast); let args = p.args().map(|p| self.collect_pat(p)).collect(); - self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr) + Pat::TupleStruct { path, args } } 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) + Pat::Ref { pat, mutability } } - _ => { - // TODO - self.alloc_pat(Pat::Missing, syntax_ptr) + ast::PatKind::PathPat(p) => { + let path = p.path().and_then(Path::from_ast); + path.map(|path| Pat::Path(path)).unwrap_or(Pat::Missing) } - } + ast::PatKind::TuplePat(p) => { + let args = p.args().map(|p| self.collect_pat(p)).collect(); + Pat::Tuple(args) + } + ast::PatKind::PlaceholderPat(_) => Pat::Wild, + // TODO: implement + ast::PatKind::FieldPatList(_) + | ast::PatKind::SlicePat(_) + | ast::PatKind::StructPat(_) + | ast::PatKind::RangePat(_) => Pat::Missing, + }; + let syntax_ptr = LocalSyntaxPtr::new(pat.syntax()); + self.alloc_pat(pattern, syntax_ptr) } fn collect_pat_opt(&mut self, pat: Option<&ast::Pat>) -> PatId { diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index c7c063601..854d3e3d9 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -1168,6 +1168,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { decl_ty }; + // TODO: walk the pattern here? + self.write_pat_ty(*pat, ty); } Statement::Expr(expr) => { @@ -1188,6 +1190,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { for (type_ref, pat) in signature.params().iter().zip(body.params()) { let ty = self.make_ty(type_ref); let ty = self.insert_type_vars(ty); + + // TODO: walk pattern? + self.write_pat_ty(*pat, ty); } self.return_ty = { diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index a430cbe88..fc1e5b09c 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -358,6 +358,21 @@ fn test(x: &str, y: isize) { ); } +#[test] +fn infer_pattern() { + check_inference( + r#" +fn test(x: &i32) { + let y = x; + let &z = x; + let a = z; + let (c, d) = (1, "hello"); +} +"#, + "pattern.txt", + ); +} + fn infer(content: &str) -> String { let (db, _, file_id) = MockDatabase::with_single_file(content); let source_file = db.source_file(file_id); diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 2d9603d90..2fd146bf1 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -2285,7 +2285,11 @@ impl AstNode for PathPat { } -impl PathPat {} +impl PathPat { + pub fn path(&self) -> Option<&Path> { + super::child_opt(self) + } +} // PathSegment #[derive(Debug, PartialEq, Eq, Hash)] @@ -3219,7 +3223,11 @@ impl AstNode for TuplePat { } -impl TuplePat {} +impl TuplePat { + pub fn args(&self) -> impl Iterator { + super::children(self) + } +} // TupleStructPat #[derive(Debug, PartialEq, Eq, Hash)] diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 2aaad46b1..b524c8aaf 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -490,14 +490,14 @@ Grammar( "RefPat": ( options: [ "Pat" ]), "BindPat": ( traits: ["NameOwner"] ), "PlaceholderPat": (), - "PathPat": (), + "PathPat": ( options: ["Path"] ), "StructPat": (), "FieldPatList": (), "TupleStructPat": ( options: ["Path"], collections: [["args", "Pat"]], ), - "TuplePat": (), + "TuplePat": ( collections: [["args", "Pat"]] ), "SlicePat": (), "RangePat": (), -- cgit v1.2.3