Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
50cbf19
add action to wrap a function ref in its own anonymous fn
treuherz Jul 16, 2025
0d3af2d
add action to unwrap a trivial anonymous function
treuherz Jul 16, 2025
c20b981
tidy imports
treuherz Jul 17, 2025
b9d6754
remove chained if-let
treuherz Jul 17, 2025
1bbf8ed
better naming, more docs and comments
treuherz Jul 17, 2025
aed14a6
add range checks for new code actions
treuherz Jul 17, 2025
e6ee64c
correctly indent gleam in tests
treuherz Jul 17, 2025
cb1bb1c
make unwrapping work within nested function literals
treuherz Jul 17, 2025
8b43e4d
anonymous functions can't have labelled arguments!
treuherz Jul 17, 2025
f3eb218
make function-wrapping action wrap any uncalled function
treuherz Jul 17, 2025
5c6aa88
add tests for unwrapping functions with labelled arguments
treuherz Jul 17, 2025
5e926a4
don't try to unwrap functions with comments in
treuherz Jul 17, 2025
6e01d2c
add test for wrapping record constructor
treuherz Jul 18, 2025
3ec71f7
use iterators for comparing arguments instead of vecs
treuherz Jul 18, 2025
9c69083
add failing tests for first_comment_between
treuherz Jul 17, 2025
9a951b0
fix first_comment_between
treuherz Jul 17, 2025
c68ea9b
unwrap anonymous functions with comments in
treuherz Jul 18, 2025
631d821
add changelog entry for new code actions
treuherz Aug 3, 2025
8884ab1
don't offer to re-wrap anonymous functions
treuherz Aug 7, 2025
a4fd477
add tests for wrapping multi-argument pipeline steps
treuherz Aug 7, 2025
6809596
don't copy comment location in a loop
treuherz Aug 7, 2025
58626bf
get fn locations from parser
treuherz Aug 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

## Unreleased

- The language server now offers code actions to wrap a function reference in an
anonymous function, or to remove a trivial anonymous function, leaving its
contents. For example:

```gleam
pub fn main() {
[-1, -2, -3] |> list.map(fn(a) { int.absolute_value(a) })
// ^^ Activating the "Remove anonymous function"
// code action here
}
```

would result in:

```gleam
pub fn main() {
[-1, -2, -3] |> list.map(int.absolute_value)
}
```

while the other action would reverse the change. ([Eli Treuherz](http.github.com/treuherz))

### Compiler

- The compiler now performs function inlining optimisations for a specific set
Expand Down
1 change: 1 addition & 0 deletions compiler-core/src/ast/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub enum TypedExpr {
type_: Arc<Type>,
fun: Box<Self>,
arguments: Vec<CallArg<Self>>,
arguments_start: Option<u32>,
},

BinOp {
Expand Down
10 changes: 9 additions & 1 deletion compiler-core/src/ast/untyped.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub enum UntypedExpr {
location: SrcSpan,
fun: Box<Self>,
arguments: Vec<CallArg<Self>>,
arguments_start: u32,
},

BinOp {
Expand Down Expand Up @@ -293,11 +294,18 @@ impl HasLocation for UntypedExpr {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FunctionLiteralKind {
Capture { hole: SrcSpan },
Anonymous { head: SrcSpan },
Anonymous { head: SrcSpan, body: SrcSpan },
Use { location: SrcSpan },
}

impl FunctionLiteralKind {
pub fn is_anonymous(&self) -> bool {
match self {
FunctionLiteralKind::Anonymous { .. } => true,
FunctionLiteralKind::Capture { .. } | FunctionLiteralKind::Use { .. } => false,
}
}

pub fn is_capture(&self) -> bool {
match self {
FunctionLiteralKind::Capture { .. } => true,
Expand Down
7 changes: 5 additions & 2 deletions compiler-core/src/ast/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,9 @@ pub trait Visit<'ast> {
type_: &'ast Arc<Type>,
fun: &'ast TypedExpr,
arguments: &'ast [TypedCallArg],
arguments_start: &'ast Option<u32>,
) {
visit_typed_expr_call(self, location, type_, fun, arguments);
visit_typed_expr_call(self, location, type_, fun, arguments, arguments_start);
}

fn visit_typed_expr_bin_op(
Expand Down Expand Up @@ -814,7 +815,8 @@ where
type_,
fun,
arguments,
} => v.visit_typed_expr_call(location, type_, fun, arguments),
arguments_start,
} => v.visit_typed_expr_call(location, type_, fun, arguments, arguments_start),
TypedExpr::BinOp {
location,
type_,
Expand Down Expand Up @@ -1049,6 +1051,7 @@ pub fn visit_typed_expr_call<'a, V>(
_type_: &'a Arc<Type>,
fun: &'a TypedExpr,
arguments: &'a [TypedCallArg],
_arguments_start: &'a Option<u32>,
) where
V: Visit<'a> + ?Sized,
{
Expand Down
7 changes: 6 additions & 1 deletion compiler-core/src/ast_folder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
location,
fun,
arguments,
} => self.fold_call(location, fun, arguments),
arguments_start,
} => self.fold_call(location, fun, arguments, arguments_start),

UntypedExpr::BinOp {
location,
Expand Down Expand Up @@ -445,6 +446,7 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
location,
fun,
arguments,
arguments_start,
} => {
let fun = Box::new(self.fold_expr(*fun));
let arguments = arguments
Expand All @@ -458,6 +460,7 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
location,
fun,
arguments,
arguments_start,
}
}

Expand Down Expand Up @@ -770,11 +773,13 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
location: SrcSpan,
fun: Box<UntypedExpr>,
arguments: Vec<CallArg<UntypedExpr>>,
arguments_start: u32,
) -> UntypedExpr {
UntypedExpr::Call {
location,
fun,
arguments,
arguments_start,
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler-core/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,7 @@ impl<'comments> Formatter<'comments> {
fun,
arguments,
location,
..
})) = call.first()
else {
// The body of a capture being not a fn shouldn't be possible...
Expand Down
6 changes: 5 additions & 1 deletion compiler-core/src/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@ impl Inliner<'_> {
type_,
fun,
arguments,
} => self.call(location, type_, fun, arguments),
arguments_start,
} => self.call(location, type_, fun, arguments, arguments_start),

TypedExpr::BinOp {
location,
Expand Down Expand Up @@ -581,6 +582,7 @@ impl Inliner<'_> {
type_: Arc<Type>,
function: Box<TypedExpr>,
arguments: Vec<TypedCallArg>,
arguments_start: Option<u32>,
) -> TypedExpr {
let arguments = self.arguments(arguments);

Expand Down Expand Up @@ -699,6 +701,7 @@ impl Inliner<'_> {
type_,
fun: Box::new(function),
arguments,
arguments_start,
}
}

Expand Down Expand Up @@ -1534,6 +1537,7 @@ impl InlinableExpression {
.iter()
.map(|argument| argument.to_call_arg(Self::to_expression))
.collect(),
arguments_start: None,
},
}
}
Expand Down
Loading
Loading