Repository: gleam-lang/gleam (rust)

Issue:
"convert to use" action - error when parameters are out of order
Issue with "convert to use" refactoring action.

When using parameter tags to call a function with "out-of-order" parameters, the refactoring action produces invalid code.

```gleam
fn refactors_okay(items) {
  list.fold(items, from: 0, with: fn (total, item) { 
    total + item 
  })
}

fn buggy(items) {
  // now the starting point "0" comes first
  list.fold(0, over: items, with: fn (total, item) {
    total + item
  })
}

// the above is valid gleam code but refactors to this invalid code
fn buggy_refactor(items) {
  use total, item <- list.fold(0) // missing the "items" parameter
  total + item
}
```

I organically arrived at out of order parameters because I had

```gleam
my_object.long_involved_constructor()
|> list.fold(over: items, with: fn (a, b) { todo })

// then I used the "inline pipe" action
list.fold(my_object.long_involved_constructor(), over: items, with: fn (a, b) { todo })

// then I used the "convert to use" action
use a, b <- list.fold(my_object.long_involved_constructor())
todo

// but now the "items" variable has gone missing
```

Gleam version 1.9.1

Pull request description:
Fix "convert to use" code action when used on function calls with labelled out-of-order arguments
If a function was called with arguments that ended up being out of order because of labels, the "convert to use" code action would end up removing more arguments than it actually should. This PR fixes this bug, closes #4498 

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4e8f60f14..e6c38e319 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -369,3 +369,8 @@
 - Fixed a bug where a using the pipe operator in the `size` option of a bit array
   segment would generate invalid code on the Erlang target.
   ([Surya Rose](https://github.com/GearsDatapacks))
+
+- Fixed a bug where the language server would generate invalid code for the
+  "convert to use" code action, when used on a function call with labelled
+  arguments.
+  ([Giacomo Cavalieri](https://github.com/giacomocavalieri))
diff --git a/compiler-core/src/language_server/code_action.rs b/compiler-core/src/language_server/code_action.rs
index 283a740ab..8988aa220 100644
--- a/compiler-core/src/language_server/code_action.rs
+++ b/compiler-core/src/language_server/code_action.rs
@@ -2701,6 +2701,16 @@ fn turn_expression_into_use(expr: &TypedExpr) -> Option<CallLocations> {
         return None;
     };
 
+    // The function arguments in the ast are reordered using function's field map.
+    // This means that in the `args` array they might not appear in the same order
+    // in which they are written by the user. Since the rest of the code relies
+    // on their order in the written code we first have to sort them by their
+    // source position.
+    let args = args
+        .iter()
+        .sorted_by_key(|arg| arg.location.start)
+        .collect_vec();
+
     let CallArg {
         value: last_arg,
         implicit: None,


Test patch:
diff --git a/compiler-core/src/language_server/tests/action.rs b/compiler-core/src/language_server/tests/action.rs
index 1ce8aff6c..572ecb1d3 100644
--- a/compiler-core/src/language_server/tests/action.rs
+++ b/compiler-core/src/language_server/tests/action.rs
@@ -4240,6 +4240,24 @@ pub fn main() {
     );
 }
 
+#[test]
+// https://github.com/gleam-lang/gleam/issues/4498
+fn turn_call_into_use_with_out_of_order_arguments() {
+    assert_code_action!(
+        CONVERT_TO_USE,
+        r#"
+pub fn main() {
+  fold(0, over: [], with: fn (a, b) { todo })
+}
+
+fn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc {
+  todo
+}
+"#,
+        find_position_of("fold").to_selection(),
+    );
+}
+
 #[test]
 fn inexhaustive_let_result_to_case() {
     assert_code_action!(
diff --git a/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__action__turn_call_into_use_with_out_of_order_arguments.snap b/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__action__turn_call_into_use_with_out_of_order_arguments.snap
new file mode 100644
index 000000000..b06af79c0
--- /dev/null
+++ b/compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__action__turn_call_into_use_with_out_of_order_arguments.snap
@@ -0,0 +1,26 @@
+---
+source: compiler-core/src/language_server/tests/action.rs
+expression: "\npub fn main() {\n  fold(0, over: [], with: fn (a, b) { todo })\n}\n\nfn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc {\n  todo\n}\n"
+---
+----- BEFORE ACTION
+
+pub fn main() {
+  fold(0, over: [], with: fn (a, b) { todo })
+  ↑                                          
+}
+
+fn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc {
+  todo
+}
+
+
+----- AFTER ACTION
+
+pub fn main() {
+  use a, b <- fold(0, over: [])
+  todo
+}
+
+fn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc {
+  todo
+}