Skip to content

Commit cb1bb1c

Browse files
committed
make unwrapping work within nested function literals
1 parent e6ee64c commit cb1bb1c

File tree

3 files changed

+75
-14
lines changed

3 files changed

+75
-14
lines changed

compiler-core/src/language_server/code_action.rs

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8385,23 +8385,22 @@ impl<'a> UnwrapAnonymousFunction<'a> {
83858385
}
83868386
actions
83878387
}
8388-
}
83898388

8390-
impl<'ast> ast::visit::Visit<'ast> for UnwrapAnonymousFunction<'ast> {
8391-
fn visit_typed_expr_fn(
8389+
/// If an anonymous function can be unwrapped, save it to our list
8390+
///
8391+
/// We need to ensure our subjects:
8392+
/// - are anonymous function literals (not captures)
8393+
/// - only contain a single statement
8394+
/// - that statement is a function call
8395+
/// - that call's arguments exactly match the arguments of the enclosing
8396+
/// function
8397+
fn register_function(
83928398
&mut self,
8393-
location: &'ast SrcSpan,
8394-
_type_: &'ast Arc<Type>,
8395-
kind: &'ast FunctionLiteralKind,
8396-
arguments: &'ast [TypedArg],
8397-
body: &'ast Vec1<TypedStatement>,
8398-
_return_annotation: &'ast Option<ast::TypeAst>,
8399+
location: &'a SrcSpan,
8400+
kind: &'a FunctionLiteralKind,
8401+
arguments: &'a [TypedArg],
8402+
body: &'a Vec1<TypedStatement>,
83998403
) {
8400-
let function_range = src_span_to_lsp_range(*location, self.line_numbers);
8401-
if !overlaps(self.params.range, function_range) {
8402-
return;
8403-
}
8404-
84058404
match kind {
84068405
FunctionLiteralKind::Anonymous { .. } => (),
84078406
_ => return,
@@ -8455,3 +8454,26 @@ impl<'ast> ast::visit::Visit<'ast> for UnwrapAnonymousFunction<'ast> {
84558454
})
84568455
}
84578456
}
8457+
8458+
impl<'ast> ast::visit::Visit<'ast> for UnwrapAnonymousFunction<'ast> {
8459+
fn visit_typed_expr_fn(
8460+
&mut self,
8461+
location: &'ast SrcSpan,
8462+
_type: &'ast Arc<Type>,
8463+
kind: &'ast FunctionLiteralKind,
8464+
arguments: &'ast [TypedArg],
8465+
body: &'ast Vec1<TypedStatement>,
8466+
_return_annotation: &'ast Option<ast::TypeAst>,
8467+
) {
8468+
let function_range = src_span_to_lsp_range(*location, self.line_numbers);
8469+
if !overlaps(self.params.range, function_range) {
8470+
return;
8471+
}
8472+
8473+
self.register_function(location, kind, arguments, body);
8474+
8475+
for statement in body {
8476+
self.visit_typed_statement(statement);
8477+
}
8478+
}
8479+
}

compiler-core/src/language_server/tests/action.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9851,6 +9851,22 @@ fn op(i: Int) -> Int {
98519851
);
98529852
}
98539853

9854+
#[test]
9855+
fn unwrap_nested_anonymous_function() {
9856+
assert_code_action!(
9857+
UNWRAP_ANONYMOUS_FUNCTION,
9858+
"pub fn main() {
9859+
fn(do) { fn(re){ mi(re) }(do) }
9860+
}
9861+
9862+
fn mi(v) {
9863+
todo
9864+
}
9865+
",
9866+
find_position_of("fn(re)").to_selection()
9867+
);
9868+
}
9869+
98549870
#[test]
98559871
fn unwrap_anonymous_function_unavailable_when_args_discarded() {
98569872
assert_no_code_actions!(
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "pub fn main() {\n fn(do) { fn(re){ mi(re) }(do) }\n}\n\nfn mi(v) {\n todo\n}\n"
4+
---
5+
----- BEFORE ACTION
6+
pub fn main() {
7+
fn(do) { fn(re){ mi(re) }(do) }
8+
9+
}
10+
11+
fn mi(v) {
12+
todo
13+
}
14+
15+
16+
----- AFTER ACTION
17+
pub fn main() {
18+
fn(do) { mi(do) }
19+
}
20+
21+
fn mi(v) {
22+
todo
23+
}

0 commit comments

Comments
 (0)