Skip to content

Commit 58626bf

Browse files
committed
get fn locations from parser
This increases the blast radius of the change a bit, but means we don't need to worry about comments any more.
1 parent 6809596 commit 58626bf

15 files changed

+126
-66
lines changed

compiler-core/src/ast/typed.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub enum TypedExpr {
7676
type_: Arc<Type>,
7777
fun: Box<Self>,
7878
arguments: Vec<CallArg<Self>>,
79+
arguments_start: Option<u32>,
7980
},
8081

8182
BinOp {

compiler-core/src/ast/untyped.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub enum UntypedExpr {
5353
location: SrcSpan,
5454
fun: Box<Self>,
5555
arguments: Vec<CallArg<Self>>,
56+
arguments_start: u32,
5657
},
5758

5859
BinOp {
@@ -293,7 +294,7 @@ impl HasLocation for UntypedExpr {
293294
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
294295
pub enum FunctionLiteralKind {
295296
Capture { hole: SrcSpan },
296-
Anonymous { head: SrcSpan },
297+
Anonymous { head: SrcSpan, body: SrcSpan },
297298
Use { location: SrcSpan },
298299
}
299300

compiler-core/src/ast/visit.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,9 @@ pub trait Visit<'ast> {
196196
type_: &'ast Arc<Type>,
197197
fun: &'ast TypedExpr,
198198
arguments: &'ast [TypedCallArg],
199+
arguments_start: &'ast Option<u32>,
199200
) {
200-
visit_typed_expr_call(self, location, type_, fun, arguments);
201+
visit_typed_expr_call(self, location, type_, fun, arguments, arguments_start);
201202
}
202203

203204
fn visit_typed_expr_bin_op(
@@ -814,7 +815,8 @@ where
814815
type_,
815816
fun,
816817
arguments,
817-
} => v.visit_typed_expr_call(location, type_, fun, arguments),
818+
arguments_start,
819+
} => v.visit_typed_expr_call(location, type_, fun, arguments, arguments_start),
818820
TypedExpr::BinOp {
819821
location,
820822
type_,
@@ -1049,6 +1051,7 @@ pub fn visit_typed_expr_call<'a, V>(
10491051
_type_: &'a Arc<Type>,
10501052
fun: &'a TypedExpr,
10511053
arguments: &'a [TypedCallArg],
1054+
_arguments_start: &'a Option<u32>,
10521055
) where
10531056
V: Visit<'a> + ?Sized,
10541057
{

compiler-core/src/ast_folder.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
289289
location,
290290
fun,
291291
arguments,
292-
} => self.fold_call(location, fun, arguments),
292+
arguments_start,
293+
} => self.fold_call(location, fun, arguments, arguments_start),
293294

294295
UntypedExpr::BinOp {
295296
location,
@@ -445,6 +446,7 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
445446
location,
446447
fun,
447448
arguments,
449+
arguments_start,
448450
} => {
449451
let fun = Box::new(self.fold_expr(*fun));
450452
let arguments = arguments
@@ -458,6 +460,7 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
458460
location,
459461
fun,
460462
arguments,
463+
arguments_start,
461464
}
462465
}
463466

@@ -770,11 +773,13 @@ pub trait UntypedExprFolder: TypeAstFolder + UntypedConstantFolder + PatternFold
770773
location: SrcSpan,
771774
fun: Box<UntypedExpr>,
772775
arguments: Vec<CallArg<UntypedExpr>>,
776+
arguments_start: u32,
773777
) -> UntypedExpr {
774778
UntypedExpr::Call {
775779
location,
776780
fun,
777781
arguments,
782+
arguments_start,
778783
}
779784
}
780785

compiler-core/src/format.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,6 +1592,7 @@ impl<'comments> Formatter<'comments> {
15921592
fun,
15931593
arguments,
15941594
location,
1595+
..
15951596
})) = call.first()
15961597
else {
15971598
// The body of a capture being not a fn shouldn't be possible...

compiler-core/src/inline.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ impl Inliner<'_> {
363363
type_,
364364
fun,
365365
arguments,
366-
} => self.call(location, type_, fun, arguments),
366+
arguments_start,
367+
} => self.call(location, type_, fun, arguments, arguments_start),
367368

368369
TypedExpr::BinOp {
369370
location,
@@ -581,6 +582,7 @@ impl Inliner<'_> {
581582
type_: Arc<Type>,
582583
function: Box<TypedExpr>,
583584
arguments: Vec<TypedCallArg>,
585+
arguments_start: Option<u32>,
584586
) -> TypedExpr {
585587
let arguments = self.arguments(arguments);
586588

@@ -699,6 +701,7 @@ impl Inliner<'_> {
699701
type_,
700702
fun: Box::new(function),
701703
arguments,
704+
arguments_start,
702705
}
703706
}
704707

@@ -1534,6 +1537,7 @@ impl InlinableExpression {
15341537
.iter()
15351538
.map(|argument| argument.to_call_arg(Self::to_expression))
15361539
.collect(),
1540+
arguments_start: None,
15371541
},
15381542
}
15391543
}

compiler-core/src/language_server/code_action.rs

Lines changed: 73 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,28 @@ fn count_indentation(code: &str, line_numbers: &LineNumbers, line: u32) -> usize
102102
indent_size
103103
}
104104

105+
// Given a string and a position in it, if the position points to whitespace,
106+
// this function returns the next position which doesn't.
107+
fn next_nonwhitespace(string: &EcoString, position: u32) -> u32 {
108+
let mut n = position;
109+
let mut chars = string[position as usize..].chars();
110+
while chars.next().is_some_and(char::is_whitespace) {
111+
n += 1;
112+
}
113+
n
114+
}
115+
116+
// Given a string and a position in it, if the position points after whitespace,
117+
// this function returns the previous position which doesn't.
118+
fn previous_nonwhitespace(string: &EcoString, position: u32) -> u32 {
119+
let mut n = position;
120+
let mut chars = string[..position as usize].chars();
121+
while chars.next_back().is_some_and(char::is_whitespace) {
122+
n -= 1;
123+
}
124+
n
125+
}
126+
105127
/// Code action to remove literal tuples in case subjects, essentially making
106128
/// the elements of the tuples into the case's subjects.
107129
///
@@ -842,6 +864,7 @@ impl<'ast> ast::visit::Visit<'ast> for FillInMissingLabelledArgs<'ast> {
842864
type_: &'ast Arc<Type>,
843865
fun: &'ast TypedExpr,
844866
arguments: &'ast [TypedCallArg],
867+
arguments_start: &'ast Option<u32>,
845868
) {
846869
let call_range = self.edits.src_span_to_lsp_range(*location);
847870
if !within(self.params.range, call_range) {
@@ -864,7 +887,7 @@ impl<'ast> ast::visit::Visit<'ast> for FillInMissingLabelledArgs<'ast> {
864887
// we're inside a nested call.
865888
let previous = self.use_right_hand_side_location;
866889
self.use_right_hand_side_location = None;
867-
ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments);
890+
ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments, arguments_start);
868891
self.use_right_hand_side_location = previous;
869892
}
870893

@@ -1263,7 +1286,7 @@ impl<'ast> ast::visit::Visit<'ast> for AddAnnotations<'_> {
12631286
let location = match kind {
12641287
// Function captures don't need any type annotations
12651288
FunctionLiteralKind::Capture { .. } => return,
1266-
FunctionLiteralKind::Anonymous { head } => head,
1289+
FunctionLiteralKind::Anonymous { head, .. } => head,
12671290
FunctionLiteralKind::Use { location } => location,
12681291
};
12691292

@@ -5269,6 +5292,7 @@ impl<'ast> ast::visit::Visit<'ast> for GenerateFunction<'ast> {
52695292
type_: &'ast Arc<Type>,
52705293
fun: &'ast TypedExpr,
52715294
arguments: &'ast [TypedCallArg],
5295+
arguments_start: &'ast Option<u32>,
52725296
) {
52735297
// If the function being called is invalid we need to generate a
52745298
// function that has the proper labels.
@@ -5302,8 +5326,7 @@ impl<'ast> ast::visit::Visit<'ast> for GenerateFunction<'ast> {
53025326
_ => {}
53035327
}
53045328
}
5305-
5306-
ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments);
5329+
ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments, arguments_start);
53075330
}
53085331
}
53095332

@@ -5626,6 +5649,7 @@ where
56265649
type_: &'ast Arc<Type>,
56275650
fun: &'ast TypedExpr,
56285651
arguments: &'ast [TypedCallArg],
5652+
arguments_start: &'ast Option<u32>,
56295653
) {
56305654
// If the function being called is invalid we need to generate a
56315655
// function that has the proper labels.
@@ -5639,7 +5663,14 @@ where
56395663
);
56405664
}
56415665
} else {
5642-
ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments);
5666+
ast::visit::visit_typed_expr_call(
5667+
self,
5668+
location,
5669+
type_,
5670+
fun,
5671+
arguments,
5672+
arguments_start,
5673+
);
56435674
}
56445675
}
56455676

@@ -6102,12 +6133,7 @@ impl<'a> InlineVariable<'a> {
61026133
}
61036134

61046135
let mut location = assignment.location;
6105-
6106-
let mut chars = self.module.code[location.end as usize..].chars();
6107-
// Delete any whitespace after the removed statement
6108-
while chars.next().is_some_and(char::is_whitespace) {
6109-
location.end += 1;
6110-
}
6136+
location.end = next_nonwhitespace(&self.module.code, location.end);
61116137

61126138
self.edits.delete(location);
61136139

@@ -6336,6 +6362,7 @@ impl<'ast> ast::visit::Visit<'ast> for ConvertToPipe<'ast> {
63366362
_type_: &'ast Arc<Type>,
63376363
fun: &'ast TypedExpr,
63386364
arguments: &'ast [TypedCallArg],
6365+
_arguments_start: &'ast Option<u32>,
63396366
) {
63406367
if arguments.iter().any(|arg| arg.is_capture_hole()) {
63416368
return;
@@ -8313,6 +8340,7 @@ impl<'ast> ast::visit::Visit<'ast> for WrapInAnonymousFunction<'ast> {
83138340
_type: &'ast Arc<Type>,
83148341
fun: &'ast TypedExpr,
83158342
arguments: &'ast [TypedCallArg],
8343+
_arguments_start: &'ast Option<u32>,
83168344
) {
83178345
// We only need to do this interception for explicit calls, so if any
83188346
// of our arguments are explicit we re-enter the visitor as usual.
@@ -8355,11 +8383,15 @@ pub struct UnwrapAnonymousFunction<'a> {
83558383

83568384
/// Helper struct, a target for [UnwrapAnonymousFunction]
83578385
struct FunctionToUnwrap {
8358-
/// Location of the anonymous function to apply the action to
8386+
/// Location of the anonymous function to apply the action to.
83598387
outer_function: SrcSpan,
8388+
/// Location of the opening brace of the anonymous function.
8389+
outer_function_body_start: u32,
83608390
/// Location of the function being called inside the anonymous function.
83618391
/// This will be all that's left after the action, plus any comments.
83628392
inner_function: SrcSpan,
8393+
// Location of the opening parenthesis of the inner function's argument list.
8394+
inner_function_arguments_start: u32,
83638395
}
83648396

83658397
impl<'a> UnwrapAnonymousFunction<'a> {
@@ -8383,25 +8415,29 @@ impl<'a> UnwrapAnonymousFunction<'a> {
83838415
for function in &self.functions {
83848416
let mut edits = TextEdits::new(self.line_numbers);
83858417

8386-
// We need to delete the anonymous function's head but preserve
8387-
// comments between it and the inner function call.
8388-
edits.delete(self.span_until_comment(SrcSpan {
8418+
// We need to delete the anonymous function's head and the opening
8419+
// brace but preserve comments between it and the inner function call.
8420+
// We set our endpoint at the start of the function body, and move
8421+
// it on through any whitespace.
8422+
let head_deletion_end =
8423+
next_nonwhitespace(&self.module.code, function.outer_function_body_start + 1);
8424+
edits.delete(SrcSpan {
83898425
start: function.outer_function.start,
8390-
end: function.inner_function.start,
8391-
}));
8392-
8393-
// Now we need to delete the inner function call's arguments,
8394-
// preserving comments before the outer function tail.
8395-
edits.delete(self.span_until_comment(SrcSpan {
8396-
start: function.inner_function.end,
8397-
end: function.outer_function.end - 1,
8398-
}));
8399-
8400-
// To delete the tail we nip one character to make sure we get the
8401-
// `}`. This could be redundant with the above if there were no
8402-
// comments, but that's fine.
8426+
end: head_deletion_end,
8427+
});
8428+
8429+
// Delete the inner function call's arguments.
8430+
edits.delete(SrcSpan {
8431+
start: function.inner_function_arguments_start,
8432+
end: function.inner_function.end,
8433+
});
8434+
8435+
// To delete the tail we remove the function end (the '}') and any
8436+
// whitespace before it.
8437+
let tail_deletion_start =
8438+
previous_nonwhitespace(&self.module.code, function.outer_function.end - 1);
84038439
edits.delete(SrcSpan {
8404-
start: function.outer_function.end - 1,
8440+
start: tail_deletion_start,
84058441
end: function.outer_function.end,
84068442
});
84078443

@@ -8413,24 +8449,6 @@ impl<'a> UnwrapAnonymousFunction<'a> {
84138449
actions
84148450
}
84158451

8416-
// Returns the given span, but with the end point adjusted to the start
8417-
// of the first comment in the span, if any.
8418-
fn span_until_comment(&self, span: SrcSpan) -> SrcSpan {
8419-
let SrcSpan { start, end } = span;
8420-
let adjusted_end = self
8421-
.module
8422-
.extra
8423-
.first_comment_between(start, end)
8424-
// The above will return the start of the comment's text, so we need
8425-
// to step backwards a bit to get the `//`.
8426-
.map(|comment| comment.start - 2)
8427-
.unwrap_or(end);
8428-
SrcSpan {
8429-
start,
8430-
end: adjusted_end,
8431-
}
8432-
}
8433-
84348452
/// If an anonymous function can be unwrapped, save it to our list
84358453
///
84368454
/// We need to ensure our subjects:
@@ -8446,16 +8464,17 @@ impl<'a> UnwrapAnonymousFunction<'a> {
84468464
arguments: &'a [TypedArg],
84478465
body: &'a Vec1<TypedStatement>,
84488466
) {
8449-
match kind {
8450-
FunctionLiteralKind::Anonymous { .. } => (),
8467+
let outer_body = match kind {
8468+
FunctionLiteralKind::Anonymous { body, .. } => body,
84518469
_ => return,
8452-
}
8470+
};
84538471

84548472
// We can only apply to anonymous functions containing a single function call
84558473
let [
84568474
TypedStatement::Expression(TypedExpr::Call {
8457-
fun: called_function,
8475+
location: call_location,
84588476
arguments: call_arguments,
8477+
arguments_start: Some(arguments_start),
84598478
..
84608479
}),
84618480
] = body.as_slice()
@@ -8490,7 +8509,9 @@ impl<'a> UnwrapAnonymousFunction<'a> {
84908509

84918510
self.functions.push(FunctionToUnwrap {
84928511
outer_function: *location,
8493-
inner_function: called_function.location(),
8512+
outer_function_body_start: outer_body.start,
8513+
inner_function: *call_location,
8514+
inner_function_arguments_start: *arguments_start,
84948515
})
84958516
}
84968517
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9976,7 +9976,6 @@ fn wobble(i) {
99769976
);
99779977
}
99789978

9979-
99809979
#[test]
99819980
fn wrap_final_pipeline_step_in_anonymous_function() {
99829981
assert_code_action!(

0 commit comments

Comments
 (0)