Skip to content

Commit 4a40121

Browse files
giacomocavalierilpil
authored andcommitted
use correct location for extracted uses
1 parent abdbcb2 commit 4a40121

File tree

4 files changed

+74
-9
lines changed

4 files changed

+74
-9
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Bug fixes
6+
7+
- Fixed a bug where the "Extract function" code action would not properly
8+
extract a `use` expression.
9+
([Giacomo Cavalieri](https://github.com/giacomocavalieri))
10+
311
## v1.13.0-rc1 - 2025-09-29
412

513
### Compiler

compiler-core/src/language_server/code_action.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8981,11 +8981,24 @@ impl<'ast> ast::visit::Visit<'ast> for ExtractFunction<'ast> {
89818981
}
89828982

89838983
fn visit_typed_statement(&mut self, statement: &'ast TypedStatement) {
8984-
let location = statement.location();
8985-
if self.can_extract(location) {
8986-
let position = if let Some(last_statement_location) = self.last_statement_location
8987-
&& location == last_statement_location
8988-
{
8984+
let statement_location = match statement {
8985+
ast::Statement::Expression(expression) => expression.location(),
8986+
ast::Statement::Assignment(assignment) => assignment.location,
8987+
ast::Statement::Assert(assert) => assert.location,
8988+
ast::Statement::Use(use_) => use_.location.merge(&use_.call.location()),
8989+
};
8990+
8991+
if self.can_extract(statement_location) {
8992+
let is_in_tail_position =
8993+
self.last_statement_location
8994+
.is_some_and(|last_statement_location| {
8995+
last_statement_location == statement_location
8996+
});
8997+
8998+
// A use is always eating up the entire block, if we're extracting it,
8999+
// it will be in tail position there and the extracted function should
9000+
// return its returned value.
9001+
let position = if statement.is_use() || is_in_tail_position {
89899002
StatementPosition::Tail {
89909003
type_: statement.type_(),
89919004
}
@@ -8996,7 +9009,7 @@ impl<'ast> ast::visit::Visit<'ast> for ExtractFunction<'ast> {
89969009
match &mut self.function {
89979010
None => {
89989011
self.function = Some(ExtractedFunction::new(ExtractedValue::Statements {
8999-
location,
9012+
location: statement_location,
90009013
position,
90019014
}));
90029015
}
@@ -9008,8 +9021,8 @@ impl<'ast> ast::visit::Visit<'ast> for ExtractFunction<'ast> {
90089021
..
90099022
}) => {}
90109023
// If we are selecting multiple statements, this statement should
9011-
// be included within list, so we merge th spans to ensure it is
9012-
// included.
9024+
// be included within list, so we merge the spans to ensure it
9025+
// is included.
90139026
Some(ExtractedFunction {
90149027
value:
90159028
ExtractedValue::Statements {
@@ -9018,7 +9031,7 @@ impl<'ast> ast::visit::Visit<'ast> for ExtractFunction<'ast> {
90189031
},
90199032
..
90209033
}) => {
9021-
*location = location.merge(&statement.location());
9034+
*location = location.merge(&statement_location);
90229035
*extracted_position = position;
90239036
}
90249037
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10554,3 +10554,20 @@ pub fn main() {
1055410554
find_position_of("let c").select_until(find_position_of("* d"))
1055510555
);
1055610556
}
10557+
10558+
#[test]
10559+
fn extract_use_in_tail_position() {
10560+
assert_code_action!(
10561+
EXTRACT_FUNCTION,
10562+
r#"
10563+
pub fn main() {
10564+
use <- wibble
10565+
123
10566+
}
10567+
10568+
fn wibble(f: fn() -> Int) -> Int { f() }
10569+
"#,
10570+
find_position_of("use").select_until(find_position_of("wibble"))
10571+
);
10572+
}
10573+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "\npub fn main() {\n use <- wibble\n 123\n}\n\nfn wibble(f: fn() -> Int) -> Int { f() }\n"
4+
---
5+
----- BEFORE ACTION
6+
7+
pub fn main() {
8+
use <- wibble
9+
▔▔▔▔▔▔▔↑
10+
123
11+
}
12+
13+
fn wibble(f: fn() -> Int) -> Int { f() }
14+
15+
16+
----- AFTER ACTION
17+
18+
pub fn main() {
19+
function()
20+
}
21+
22+
fn function() -> Int {
23+
use <- wibble
24+
123
25+
}
26+
27+
fn wibble(f: fn() -> Int) -> Int { f() }

0 commit comments

Comments
 (0)