Skip to content

Commit 1bbf8ed

Browse files
committed
better naming, more docs and comments
1 parent b9d6754 commit 1bbf8ed

File tree

2 files changed

+86
-44
lines changed

2 files changed

+86
-44
lines changed

compiler-core/src/language_server/code_action.rs

Lines changed: 85 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3503,11 +3503,13 @@ impl<'ast> ast::visit::Visit<'ast> for ExpandFunctionCapture<'ast> {
35033503
}
35043504
}
35053505

3506+
/// A set of variable names used in some gleam. Useful for passing to [NameGenerator::reserve_variable_names].
35063507
struct VariablesNames {
35073508
names: HashSet<EcoString>,
35083509
}
35093510

35103511
impl VariablesNames {
3512+
/// Creates a `VariableNames` by collecting all variables used in a list of statements.
35113513
fn from_statements(statements: &[TypedStatement]) -> Self {
35123514
let mut variables = Self {
35133515
names: HashSet::new(),
@@ -3519,12 +3521,13 @@ impl VariablesNames {
35193521
variables
35203522
}
35213523

3522-
fn from_expr(expr: &TypedExpr) -> Self {
3524+
/// Creates a `VariableNames` by collecting all variables used within an expression.
3525+
fn from_expression(expression: &TypedExpr) -> Self {
35233526
let mut variables = Self {
35243527
names: HashSet::new(),
35253528
};
35263529

3527-
variables.visit_typed_expr(expr);
3530+
variables.visit_typed_expr(expression);
35283531
variables
35293532
}
35303533
}
@@ -8206,17 +8209,33 @@ impl<'ast> ast::visit::Visit<'ast> for RemoveUnreachableBranches<'ast> {
82068209
}
82078210
}
82088211

8209-
struct FunctionToWrap {
8210-
location: SrcSpan,
8211-
arguments: Vec<Arc<Type>>,
8212-
variables_names: VariablesNames,
8213-
}
8214-
8212+
/// Code action to turn a function used as a reference into a one-statement anonymous function.
8213+
///
8214+
/// For example, if the code action was used on `op` here:
8215+
///
8216+
/// ```gleam
8217+
/// list.map([1, 2, 3], op)
8218+
/// ```
8219+
///
8220+
/// it would become:
8221+
///
8222+
/// ```gleam
8223+
/// list.map([1, 2, 3], fn(int) {
8224+
/// op(int)
8225+
/// })
8226+
/// ```
82158227
pub struct WrapInAnonymousFunction<'a> {
82168228
module: &'a Module,
82178229
line_numbers: &'a LineNumbers,
82188230
params: &'a CodeActionParams,
8219-
targets: Vec<FunctionToWrap>,
8231+
functions: Vec<FunctionToWrap>,
8232+
}
8233+
8234+
/// Helper struct, a target for [WrapInAnonymousFunction].
8235+
struct FunctionToWrap {
8236+
location: SrcSpan,
8237+
arguments: Vec<Arc<Type>>,
8238+
variables_names: VariablesNames,
82208239
}
82218240

82228241
impl<'a> WrapInAnonymousFunction<'a> {
@@ -8229,15 +8248,15 @@ impl<'a> WrapInAnonymousFunction<'a> {
82298248
module,
82308249
line_numbers,
82318250
params,
8232-
targets: vec![],
8251+
functions: vec![],
82338252
}
82348253
}
82358254

82368255
pub fn code_actions(mut self) -> Vec<CodeAction> {
82378256
self.visit_typed_module(&self.module.ast);
82388257

8239-
let mut actions = Vec::with_capacity(self.targets.len());
8240-
for target in self.targets {
8258+
let mut actions = Vec::with_capacity(self.functions.len());
8259+
for target in self.functions {
82418260
let mut name_generator = NameGenerator::new();
82428261
name_generator.reserve_variable_names(target.variables_names);
82438262
let arguments = target
@@ -8262,9 +8281,9 @@ impl<'a> WrapInAnonymousFunction<'a> {
82628281
impl<'ast> ast::visit::Visit<'ast> for WrapInAnonymousFunction<'ast> {
82638282
fn visit_typed_call_arg(&mut self, arg: &'ast TypedCallArg) {
82648283
if let Type::Fn { ref arguments, .. } = *arg.value.type_() {
8265-
let variables_names = VariablesNames::from_expr(&arg.value);
8284+
let variables_names = VariablesNames::from_expression(&arg.value);
82668285

8267-
self.targets.push(FunctionToWrap {
8286+
self.functions.push(FunctionToWrap {
82688287
location: arg.location,
82698288
arguments: arguments.clone(),
82708289
variables_names,
@@ -8278,9 +8297,9 @@ impl<'ast> ast::visit::Visit<'ast> for WrapInAnonymousFunction<'ast> {
82788297
}
82798298

82808299
if let Type::Fn { ref arguments, .. } = *assignment.value.type_() {
8281-
let variables_names = VariablesNames::from_expr(&assignment.value);
8300+
let variables_names = VariablesNames::from_expression(&assignment.value);
82828301

8283-
self.targets.push(FunctionToWrap {
8302+
self.functions.push(FunctionToWrap {
82848303
location: assignment.value.location(),
82858304
arguments: arguments.clone(),
82868305
variables_names,
@@ -8289,15 +8308,33 @@ impl<'ast> ast::visit::Visit<'ast> for WrapInAnonymousFunction<'ast> {
82898308
}
82908309
}
82918310

8311+
/// Code action to unwrap trivial one-statement anonymous functions into just a reference to the function called
8312+
///
8313+
/// For example, if the code action was used on the anonymous function here:
8314+
///
8315+
/// ```gleam
8316+
/// list.map([1, 2, 3], fn(int) {
8317+
/// op(int)
8318+
/// })
8319+
/// ```
8320+
///
8321+
/// it would become:
8322+
///
8323+
/// ```gleam
8324+
/// list.map([1, 2, 3], op)
8325+
/// ```
82928326
pub struct UnwrapAnonymousFunction<'a> {
82938327
module: &'a Module,
82948328
line_numbers: &'a LineNumbers,
82958329
params: &'a CodeActionParams,
8296-
targets: Vec<FnToUnwrap>,
8330+
functions: Vec<FunctionToUnwrap>,
82978331
}
82988332

8299-
struct FnToUnwrap {
8300-
fn_location: SrcSpan,
8333+
/// Helper struct, a target for [UnwrapAnonymousFunction]
8334+
struct FunctionToUnwrap {
8335+
/// Location of the anonymous function to apply the action to
8336+
anonymous_function_location: SrcSpan,
8337+
/// Location of the function being called inside the anonymous function. This will be all that's left after the action.
83018338
inner_function_location: SrcSpan,
83028339
}
83038340

@@ -8311,27 +8348,27 @@ impl<'a> UnwrapAnonymousFunction<'a> {
83118348
module,
83128349
line_numbers,
83138350
params,
8314-
targets: vec![],
8351+
functions: vec![],
83158352
}
83168353
}
83178354

83188355
pub fn code_actions(mut self) -> Vec<CodeAction> {
83198356
self.visit_typed_module(&self.module.ast);
83208357

8321-
let mut actions = Vec::with_capacity(self.targets.len());
8322-
for target in self.targets {
8358+
let mut actions = Vec::with_capacity(self.functions.len());
8359+
for target in self.functions {
83238360
let mut edits = TextEdits::new(self.line_numbers);
83248361

83258362
edits.delete(SrcSpan {
8326-
start: target.fn_location.start,
8363+
start: target.anonymous_function_location.start,
83278364
end: target.inner_function_location.start,
83288365
});
83298366
edits.delete(SrcSpan {
83308367
start: target.inner_function_location.end,
8331-
end: target.fn_location.end,
8368+
end: target.anonymous_function_location.end,
83328369
});
83338370

8334-
CodeActionBuilder::new("Unwrap anonymous function")
8371+
CodeActionBuilder::new("Remove anonymous function wrapper")
83358372
.kind(CodeActionKind::REFACTOR_REWRITE)
83368373
.changes(self.params.text_document.uri.clone(), edits.edits)
83378374
.push_to(&mut actions);
@@ -8355,19 +8392,6 @@ impl<'ast> ast::visit::Visit<'ast> for UnwrapAnonymousFunction<'ast> {
83558392
_ => return,
83568393
}
83578394

8358-
// We need the existing argument list for the fn to be a 1:1 match for the args we pass
8359-
// to the called function. We figure out what the call-arg list needs to look like here,
8360-
// and bail out if any incoming args are discarded.
8361-
let mut expected_argument_names = Vec::with_capacity(arguments.len());
8362-
for a in arguments {
8363-
match &a.names {
8364-
ArgNames::Named { name, .. } => expected_argument_names.push(name),
8365-
ArgNames::NamedLabelled { name, .. } => expected_argument_names.push(name),
8366-
ArgNames::Discard { .. } => return,
8367-
ArgNames::LabelledDiscard { .. } => return,
8368-
}
8369-
}
8370-
83718395
// We can only apply to anonymous functions containing a single function call
83728396
let [
83738397
TypedStatement::Expression(TypedExpr::Call {
@@ -8380,20 +8404,38 @@ impl<'ast> ast::visit::Visit<'ast> for UnwrapAnonymousFunction<'ast> {
83808404
return;
83818405
};
83828406

8383-
let mut call_argument_names = Vec::with_capacity(arguments.len());
8407+
// We need the existing argument list for the fn to be a 1:1 match for
8408+
// the args we pass to the called function, so we need to collect the
8409+
// names used in both lists and check they're equal.
8410+
8411+
let mut outer_argument_names = Vec::with_capacity(arguments.len());
8412+
for a in arguments {
8413+
match &a.names {
8414+
ArgNames::Named { name, .. } => outer_argument_names.push(name),
8415+
ArgNames::NamedLabelled { name, .. } => outer_argument_names.push(name),
8416+
// We can bail out early if any of these are discarded, since
8417+
// they couldn't match the arguments used.
8418+
ArgNames::Discard { .. } => return,
8419+
ArgNames::LabelledDiscard { .. } => return,
8420+
}
8421+
}
8422+
8423+
let mut inner_argument_names = Vec::with_capacity(arguments.len());
83848424
for a in call_arguments {
83858425
match &a.value {
8386-
TypedExpr::Var { name, .. } => call_argument_names.push(name),
8426+
TypedExpr::Var { name, .. } => inner_argument_names.push(name),
8427+
// We can bail out early if any of these aren't variables, since
8428+
// they couldn't match the inputs.
83878429
_ => return,
83888430
}
83898431
}
83908432

8391-
if call_argument_names != expected_argument_names {
8433+
if inner_argument_names != outer_argument_names {
83928434
return;
83938435
}
83948436

8395-
self.targets.push(FnToUnwrap {
8396-
fn_location: *location,
8437+
self.functions.push(FunctionToUnwrap {
8438+
anonymous_function_location: *location,
83978439
inner_function_location: called_function.location(),
83988440
})
83998441
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ const REMOVE_OPAQUE_FROM_PRIVATE_TYPE: &str = "Remove opaque from private type";
135135
const COLLAPSE_NESTED_CASE: &str = "Collapse nested case";
136136
const REMOVE_UNREACHABLE_BRANCHES: &str = "Remove unreachable branches";
137137
const WRAP_IN_ANONYMOUS_FUNCTION: &str = "Wrap in anonymous function";
138-
const UNWRAP_ANONYMOUS_FUNCTION: &str = "Unwrap anonymous function";
138+
const UNWRAP_ANONYMOUS_FUNCTION: &str = "Remove anonymous function wrapper";
139139

140140
macro_rules! assert_code_action {
141141
($title:expr, $code:literal, $range:expr $(,)?) => {

0 commit comments

Comments
 (0)