diff options
-rw-r--r-- | crates/libeditor/src/code_actions.rs | 9 | ||||
-rw-r--r-- | crates/libeditor/src/scope/fn_scope.rs | 83 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/generated.rs | 86 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/mod.rs | 6 | ||||
-rw-r--r-- | crates/libsyntax2/src/grammar.ron | 28 | ||||
-rw-r--r-- | crates/libsyntax2/src/grammar/expressions/atom.rs | 7 |
6 files changed, 202 insertions, 17 deletions
diff --git a/crates/libeditor/src/code_actions.rs b/crates/libeditor/src/code_actions.rs index 684b8243a..08a85f6e2 100644 --- a/crates/libeditor/src/code_actions.rs +++ b/crates/libeditor/src/code_actions.rs | |||
@@ -80,7 +80,9 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> | |||
80 | buf.push_str(" "); | 80 | buf.push_str(" "); |
81 | buf.push_str(name.text().as_str()); | 81 | buf.push_str(name.text().as_str()); |
82 | if let Some(type_params) = type_params { | 82 | if let Some(type_params) = type_params { |
83 | join(type_params.type_params().filter_map(|it| it.name()).map(|it| it.text())) | 83 | let lifetime_params = type_params.lifetime_params().filter_map(|it| it.lifetime()).map(|it| it.text()); |
84 | let type_params = type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()); | ||
85 | join(lifetime_params.chain(type_params)) | ||
84 | .surround_with("<", ">") | 86 | .surround_with("<", ">") |
85 | .to_buf(&mut buf); | 87 | .to_buf(&mut buf); |
86 | } | 88 | } |
@@ -146,6 +148,11 @@ mod tests { | |||
146 | "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}", | 148 | "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}", |
147 | |file, off| add_impl(file, off).map(|f| f()), | 149 | |file, off| add_impl(file, off).map(|f| f()), |
148 | ); | 150 | ); |
151 | check_action( | ||
152 | "struct Foo<'a, T: Foo<'a>> {<|>}", | ||
153 | "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n<|>\n}", | ||
154 | |file, off| add_impl(file, off).map(|f| f()), | ||
155 | ); | ||
149 | } | 156 | } |
150 | 157 | ||
151 | } | 158 | } |
diff --git a/crates/libeditor/src/scope/fn_scope.rs b/crates/libeditor/src/scope/fn_scope.rs index e807c6c71..a38647c43 100644 --- a/crates/libeditor/src/scope/fn_scope.rs +++ b/crates/libeditor/src/scope/fn_scope.rs | |||
@@ -24,11 +24,7 @@ impl FnScopes { | |||
24 | scope_for: HashMap::new() | 24 | scope_for: HashMap::new() |
25 | }; | 25 | }; |
26 | let root = scopes.root_scope(); | 26 | let root = scopes.root_scope(); |
27 | fn_def.param_list().into_iter() | 27 | scopes.add_params_bindings(root, fn_def.param_list()); |
28 | .flat_map(|it| it.params()) | ||
29 | .filter_map(|it| it.pat()) | ||
30 | .for_each(|it| scopes.add_bindings(root, it)); | ||
31 | |||
32 | if let Some(body) = fn_def.body() { | 28 | if let Some(body) = fn_def.body() { |
33 | compute_block_scopes(body, &mut scopes, root) | 29 | compute_block_scopes(body, &mut scopes, root) |
34 | } | 30 | } |
@@ -56,6 +52,12 @@ impl FnScopes { | |||
56 | .filter_map(ScopeEntry::new); | 52 | .filter_map(ScopeEntry::new); |
57 | self.scopes[scope].entries.extend(entries); | 53 | self.scopes[scope].entries.extend(entries); |
58 | } | 54 | } |
55 | fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) { | ||
56 | params.into_iter() | ||
57 | .flat_map(|it| it.params()) | ||
58 | .filter_map(|it| it.pat()) | ||
59 | .for_each(|it| self.add_bindings(scope, it)); | ||
60 | } | ||
59 | fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) { | 61 | fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) { |
60 | self.scope_for.insert(node.owned(), scope); | 62 | self.scope_for.insert(node.owned(), scope); |
61 | } | 63 | } |
@@ -102,13 +104,14 @@ fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: Sco | |||
102 | for stmt in block.statements() { | 104 | for stmt in block.statements() { |
103 | match stmt { | 105 | match stmt { |
104 | ast::Stmt::LetStmt(stmt) => { | 106 | ast::Stmt::LetStmt(stmt) => { |
107 | if let Some(expr) = stmt.initializer() { | ||
108 | scopes.set_scope(expr.syntax(), scope); | ||
109 | compute_expr_scopes(expr, scopes, scope); | ||
110 | } | ||
105 | scope = scopes.new_scope(scope); | 111 | scope = scopes.new_scope(scope); |
106 | if let Some(pat) = stmt.pat() { | 112 | if let Some(pat) = stmt.pat() { |
107 | scopes.add_bindings(scope, pat); | 113 | scopes.add_bindings(scope, pat); |
108 | } | 114 | } |
109 | if let Some(expr) = stmt.initializer() { | ||
110 | scopes.set_scope(expr.syntax(), scope) | ||
111 | } | ||
112 | } | 115 | } |
113 | ast::Stmt::ExprStmt(expr_stmt) => { | 116 | ast::Stmt::ExprStmt(expr_stmt) => { |
114 | if let Some(expr) = expr_stmt.expr() { | 117 | if let Some(expr) = expr_stmt.expr() { |
@@ -163,6 +166,20 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | |||
163 | compute_block_scopes(block, scopes, scope); | 166 | compute_block_scopes(block, scopes, scope); |
164 | } | 167 | } |
165 | }, | 168 | }, |
169 | ast::Expr::LambdaExpr(e) => { | ||
170 | let mut scope = scopes.new_scope(scope); | ||
171 | scopes.add_params_bindings(scope, e.param_list()); | ||
172 | if let Some(body) = e.body() { | ||
173 | scopes.set_scope(body.syntax(), scope); | ||
174 | compute_expr_scopes(body, scopes, scope); | ||
175 | } | ||
176 | } | ||
177 | ast::Expr::CallExpr(e) => { | ||
178 | e.arg_list().into_iter() | ||
179 | .flat_map(|it| it.args()) | ||
180 | .chain(e.expr()) | ||
181 | .for_each(|expr| compute_expr_scopes(expr, scopes, scope)); | ||
182 | } | ||
166 | _ => { | 183 | _ => { |
167 | expr.syntax().children() | 184 | expr.syntax().children() |
168 | .filter_map(ast::Expr::cast) | 185 | .filter_map(ast::Expr::cast) |
@@ -189,3 +206,53 @@ struct ScopeData { | |||
189 | parent: Option<ScopeId>, | 206 | parent: Option<ScopeId>, |
190 | entries: Vec<ScopeEntry> | 207 | entries: Vec<ScopeEntry> |
191 | } | 208 | } |
209 | |||
210 | #[cfg(test)] | ||
211 | mod tests { | ||
212 | use super::*; | ||
213 | use libsyntax2::File; | ||
214 | use {find_node_at_offset, test_utils::extract_offset}; | ||
215 | |||
216 | fn do_check(code: &str, expected: &[&str]) { | ||
217 | let (off, code) = extract_offset(code); | ||
218 | let code = { | ||
219 | let mut buf = String::new(); | ||
220 | let off = u32::from(off) as usize; | ||
221 | buf.push_str(&code[..off]); | ||
222 | buf.push_str("marker"); | ||
223 | buf.push_str(&code[off..]); | ||
224 | buf | ||
225 | }; | ||
226 | let file = File::parse(&code); | ||
227 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | ||
228 | let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | ||
229 | let scopes = FnScopes::new(fn_def); | ||
230 | let actual = scopes.scope_chain(marker.syntax()) | ||
231 | .flat_map(|scope| scopes.entries(scope)) | ||
232 | .map(|it| it.name()) | ||
233 | .collect::<Vec<_>>(); | ||
234 | assert_eq!(expected, actual.as_slice()); | ||
235 | } | ||
236 | |||
237 | #[test] | ||
238 | fn test_lambda_scope() { | ||
239 | do_check(r" | ||
240 | fn quux(foo: i32) { | ||
241 | let f = |bar| { | ||
242 | <|> | ||
243 | }; | ||
244 | }", | ||
245 | &["bar", "foo"], | ||
246 | ); | ||
247 | } | ||
248 | |||
249 | #[test] | ||
250 | fn test_call_scope() { | ||
251 | do_check(r" | ||
252 | fn quux() { | ||
253 | f(|x| <|> ); | ||
254 | }", | ||
255 | &["x"], | ||
256 | ); | ||
257 | } | ||
258 | } | ||
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs index e8743caa8..d72e2091a 100644 --- a/crates/libsyntax2/src/ast/generated.rs +++ b/crates/libsyntax2/src/ast/generated.rs | |||
@@ -4,6 +4,28 @@ use { | |||
4 | SyntaxKind::*, | 4 | SyntaxKind::*, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | // ArgList | ||
8 | #[derive(Debug, Clone, Copy)] | ||
9 | pub struct ArgList<'a> { | ||
10 | syntax: SyntaxNodeRef<'a>, | ||
11 | } | ||
12 | |||
13 | impl<'a> AstNode<'a> for ArgList<'a> { | ||
14 | fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { | ||
15 | match syntax.kind() { | ||
16 | ARG_LIST => Some(ArgList { syntax }), | ||
17 | _ => None, | ||
18 | } | ||
19 | } | ||
20 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } | ||
21 | } | ||
22 | |||
23 | impl<'a> ArgList<'a> { | ||
24 | pub fn args(self) -> impl Iterator<Item = Expr<'a>> + 'a { | ||
25 | super::children(self) | ||
26 | } | ||
27 | } | ||
28 | |||
7 | // ArrayExpr | 29 | // ArrayExpr |
8 | #[derive(Debug, Clone, Copy)] | 30 | #[derive(Debug, Clone, Copy)] |
9 | pub struct ArrayExpr<'a> { | 31 | pub struct ArrayExpr<'a> { |
@@ -181,7 +203,15 @@ impl<'a> AstNode<'a> for CallExpr<'a> { | |||
181 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } | 203 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } |
182 | } | 204 | } |
183 | 205 | ||
184 | impl<'a> CallExpr<'a> {} | 206 | impl<'a> CallExpr<'a> { |
207 | pub fn expr(self) -> Option<Expr<'a>> { | ||
208 | super::child_opt(self) | ||
209 | } | ||
210 | |||
211 | pub fn arg_list(self) -> Option<ArgList<'a>> { | ||
212 | super::child_opt(self) | ||
213 | } | ||
214 | } | ||
185 | 215 | ||
186 | // CastExpr | 216 | // CastExpr |
187 | #[derive(Debug, Clone, Copy)] | 217 | #[derive(Debug, Clone, Copy)] |
@@ -705,7 +735,15 @@ impl<'a> AstNode<'a> for LambdaExpr<'a> { | |||
705 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } | 735 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } |
706 | } | 736 | } |
707 | 737 | ||
708 | impl<'a> LambdaExpr<'a> {} | 738 | impl<'a> LambdaExpr<'a> { |
739 | pub fn param_list(self) -> Option<ParamList<'a>> { | ||
740 | super::child_opt(self) | ||
741 | } | ||
742 | |||
743 | pub fn body(self) -> Option<Expr<'a>> { | ||
744 | super::child_opt(self) | ||
745 | } | ||
746 | } | ||
709 | 747 | ||
710 | // LetStmt | 748 | // LetStmt |
711 | #[derive(Debug, Clone, Copy)] | 749 | #[derive(Debug, Clone, Copy)] |
@@ -733,6 +771,46 @@ impl<'a> LetStmt<'a> { | |||
733 | } | 771 | } |
734 | } | 772 | } |
735 | 773 | ||
774 | // Lifetime | ||
775 | #[derive(Debug, Clone, Copy)] | ||
776 | pub struct Lifetime<'a> { | ||
777 | syntax: SyntaxNodeRef<'a>, | ||
778 | } | ||
779 | |||
780 | impl<'a> AstNode<'a> for Lifetime<'a> { | ||
781 | fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { | ||
782 | match syntax.kind() { | ||
783 | LIFETIME => Some(Lifetime { syntax }), | ||
784 | _ => None, | ||
785 | } | ||
786 | } | ||
787 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } | ||
788 | } | ||
789 | |||
790 | impl<'a> Lifetime<'a> {} | ||
791 | |||
792 | // LifetimeParam | ||
793 | #[derive(Debug, Clone, Copy)] | ||
794 | pub struct LifetimeParam<'a> { | ||
795 | syntax: SyntaxNodeRef<'a>, | ||
796 | } | ||
797 | |||
798 | impl<'a> AstNode<'a> for LifetimeParam<'a> { | ||
799 | fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { | ||
800 | match syntax.kind() { | ||
801 | LIFETIME_PARAM => Some(LifetimeParam { syntax }), | ||
802 | _ => None, | ||
803 | } | ||
804 | } | ||
805 | fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax } | ||
806 | } | ||
807 | |||
808 | impl<'a> LifetimeParam<'a> { | ||
809 | pub fn lifetime(self) -> Option<Lifetime<'a>> { | ||
810 | super::child_opt(self) | ||
811 | } | ||
812 | } | ||
813 | |||
736 | // Literal | 814 | // Literal |
737 | #[derive(Debug, Clone, Copy)] | 815 | #[derive(Debug, Clone, Copy)] |
738 | pub struct Literal<'a> { | 816 | pub struct Literal<'a> { |
@@ -1813,6 +1891,10 @@ impl<'a> TypeParamList<'a> { | |||
1813 | pub fn type_params(self) -> impl Iterator<Item = TypeParam<'a>> + 'a { | 1891 | pub fn type_params(self) -> impl Iterator<Item = TypeParam<'a>> + 'a { |
1814 | super::children(self) | 1892 | super::children(self) |
1815 | } | 1893 | } |
1894 | |||
1895 | pub fn lifetime_params(self) -> impl Iterator<Item = LifetimeParam<'a>> + 'a { | ||
1896 | super::children(self) | ||
1897 | } | ||
1816 | } | 1898 | } |
1817 | 1899 | ||
1818 | // TypeRef | 1900 | // TypeRef |
diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs index 9941138a7..3b5e9269f 100644 --- a/crates/libsyntax2/src/ast/mod.rs +++ b/crates/libsyntax2/src/ast/mod.rs | |||
@@ -67,6 +67,12 @@ impl<'a> Attr<'a> { | |||
67 | } | 67 | } |
68 | } | 68 | } |
69 | 69 | ||
70 | impl<'a> Lifetime<'a> { | ||
71 | pub fn text(&self) -> SmolStr { | ||
72 | self.syntax().leaf_text().unwrap() | ||
73 | } | ||
74 | } | ||
75 | |||
70 | impl<'a> Name<'a> { | 76 | impl<'a> Name<'a> { |
71 | pub fn text(&self) -> SmolStr { | 77 | pub fn text(&self) -> SmolStr { |
72 | let ident = self.syntax().first_child() | 78 | let ident = self.syntax().first_child() |
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron index f1907d1ce..3c293d3e4 100644 --- a/crates/libsyntax2/src/grammar.ron +++ b/crates/libsyntax2/src/grammar.ron | |||
@@ -344,7 +344,12 @@ Grammar( | |||
344 | "ArrayExpr": (), | 344 | "ArrayExpr": (), |
345 | "ParenExpr": (), | 345 | "ParenExpr": (), |
346 | "PathExpr": (), | 346 | "PathExpr": (), |
347 | "LambdaExpr": (), | 347 | "LambdaExpr": ( |
348 | options: [ | ||
349 | ["param_list", "ParamList"], | ||
350 | ["body", "Expr"], | ||
351 | ] | ||
352 | ), | ||
348 | "IfExpr": ( | 353 | "IfExpr": ( |
349 | options: [ ["condition", "Condition"] ] | 354 | options: [ ["condition", "Condition"] ] |
350 | ), | 355 | ), |
@@ -378,7 +383,12 @@ Grammar( | |||
378 | "StructLit": (), | 383 | "StructLit": (), |
379 | "NamedFieldList": (), | 384 | "NamedFieldList": (), |
380 | "NamedField": (), | 385 | "NamedField": (), |
381 | "CallExpr": (), | 386 | "CallExpr": ( |
387 | options: [ | ||
388 | [ "expr", "Expr" ], | ||
389 | [ "arg_list", "ArgList" ], | ||
390 | ] | ||
391 | ), | ||
382 | "IndexExpr": (), | 392 | "IndexExpr": (), |
383 | "MethodCallExpr": (), | 393 | "MethodCallExpr": (), |
384 | "FieldExpr": (), | 394 | "FieldExpr": (), |
@@ -457,8 +467,15 @@ Grammar( | |||
457 | "NameRef": (), | 467 | "NameRef": (), |
458 | "Attr": ( options: [ ["value", "TokenTree"] ] ), | 468 | "Attr": ( options: [ ["value", "TokenTree"] ] ), |
459 | "TokenTree": (), | 469 | "TokenTree": (), |
460 | "TypeParamList": ( collections: [ ["type_params", "TypeParam" ] ]), | 470 | "TypeParamList": ( |
471 | collections: [ | ||
472 | ["type_params", "TypeParam" ], | ||
473 | ["lifetime_params", "LifetimeParam" ], | ||
474 | ] | ||
475 | ), | ||
461 | "TypeParam": ( traits: ["NameOwner"] ), | 476 | "TypeParam": ( traits: ["NameOwner"] ), |
477 | "LifetimeParam": ( options: [ ["lifetime", "Lifetime"] ] ), | ||
478 | "Lifetime": (), | ||
462 | "WhereClause": (), | 479 | "WhereClause": (), |
463 | "ExprStmt": ( | 480 | "ExprStmt": ( |
464 | options: [ ["expr", "Expr"] ] | 481 | options: [ ["expr", "Expr"] ] |
@@ -492,5 +509,10 @@ Grammar( | |||
492 | ), | 509 | ), |
493 | "UseItem": (), | 510 | "UseItem": (), |
494 | "ExternCrateItem": (), | 511 | "ExternCrateItem": (), |
512 | "ArgList": ( | ||
513 | collections: [ | ||
514 | ["args", "Expr"] | ||
515 | ] | ||
516 | ) | ||
495 | }, | 517 | }, |
496 | ) | 518 | ) |
diff --git a/crates/libsyntax2/src/grammar/expressions/atom.rs b/crates/libsyntax2/src/grammar/expressions/atom.rs index 0769bb5a8..a17c27b31 100644 --- a/crates/libsyntax2/src/grammar/expressions/atom.rs +++ b/crates/libsyntax2/src/grammar/expressions/atom.rs | |||
@@ -151,10 +151,11 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker { | |||
151 | p.eat(MOVE_KW); | 151 | p.eat(MOVE_KW); |
152 | params::param_list_opt_types(p); | 152 | params::param_list_opt_types(p); |
153 | if opt_fn_ret_type(p) { | 153 | if opt_fn_ret_type(p) { |
154 | block(p); | 154 | if !p.at(L_CURLY) { |
155 | } else { | 155 | p.error("expected `{`"); |
156 | expr(p); | 156 | } |
157 | } | 157 | } |
158 | expr(p); | ||
158 | m.complete(p, LAMBDA_EXPR) | 159 | m.complete(p, LAMBDA_EXPR) |
159 | } | 160 | } |
160 | 161 | ||