aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-28 21:59:57 +0100
committerAleksey Kladov <[email protected]>2018-08-28 21:59:57 +0100
commit15f15d92eb4d6ab791047eefbd6dd9b2baba1140 (patch)
tree3f8fde6b53446c9ecfeac4f6bd2f34da5a91aa33 /crates
parentba02a55330d2ec9a0ea2c5cd457b82782ae299e9 (diff)
add impl works with lifetimes
Diffstat (limited to 'crates')
-rw-r--r--crates/libeditor/src/code_actions.rs9
-rw-r--r--crates/libeditor/src/scope/fn_scope.rs83
-rw-r--r--crates/libsyntax2/src/ast/generated.rs86
-rw-r--r--crates/libsyntax2/src/ast/mod.rs6
-rw-r--r--crates/libsyntax2/src/grammar.ron28
-rw-r--r--crates/libsyntax2/src/grammar/expressions/atom.rs7
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)]
211mod 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)]
9pub struct ArgList<'a> {
10 syntax: SyntaxNodeRef<'a>,
11}
12
13impl<'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
23impl<'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)]
9pub struct ArrayExpr<'a> { 31pub 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
184impl<'a> CallExpr<'a> {} 206impl<'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
708impl<'a> LambdaExpr<'a> {} 738impl<'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)]
776pub struct Lifetime<'a> {
777 syntax: SyntaxNodeRef<'a>,
778}
779
780impl<'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
790impl<'a> Lifetime<'a> {}
791
792// LifetimeParam
793#[derive(Debug, Clone, Copy)]
794pub struct LifetimeParam<'a> {
795 syntax: SyntaxNodeRef<'a>,
796}
797
798impl<'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
808impl<'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)]
738pub struct Literal<'a> { 816pub 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
70impl<'a> Lifetime<'a> {
71 pub fn text(&self) -> SmolStr {
72 self.syntax().leaf_text().unwrap()
73 }
74}
75
70impl<'a> Name<'a> { 76impl<'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