Skip to content

Commit 5c2bff1

Browse files
giacomocavalierilpil
authored andcommitted
do not use nested patterns when pattern matching on case variable
1 parent 4b5a41d commit 5c2bff1

6 files changed

+93
-45
lines changed

CHANGELOG.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,8 @@
227227
```gleam
228228
pub fn main() {
229229
case find_user() {
230-
Ok(user) ->
231-
case user {
232-
Admin -> todo
233-
Member -> todo
234-
}
230+
Ok(Admin) -> todo
231+
Ok(Member) -> todo
235232
Error(_) -> todo
236233
}
237234
}

compiler-core/src/language_server/code_action.rs

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4321,7 +4321,7 @@ pub struct PatternMatchOnValue<'a, A> {
43214321
module: &'a Module,
43224322
params: &'a CodeActionParams,
43234323
compiler: &'a LspProjectCompiler<A>,
4324-
pattern_variable_under_cursor: Option<(&'a EcoString, Arc<Type>)>,
4324+
pattern_variable_under_cursor: Option<(&'a EcoString, SrcSpan, Arc<Type>)>,
43254325
selected_value: Option<PatternMatchedValue<'a>>,
43264326
edits: TextEdits<'a>,
43274327
}
@@ -4362,9 +4362,8 @@ pub enum PatternMatchedValue<'a> {
43624362
/// ```
43634363
///
43644364
ClausePatternVariable {
4365-
variable_name: &'a EcoString,
43664365
variable_type: Arc<Type>,
4367-
clause_body_location: SrcSpan,
4366+
variable_location: SrcSpan,
43684367
clause_location: SrcSpan,
43694368
},
43704369
UseVariable {
@@ -4426,17 +4425,11 @@ where
44264425
}
44274426

44284427
Some(PatternMatchedValue::ClausePatternVariable {
4429-
variable_name,
44304428
variable_type,
4431-
clause_body_location,
4429+
variable_location,
44324430
clause_location,
44334431
}) => {
4434-
self.match_on_clause_variable(
4435-
variable_name,
4436-
variable_type,
4437-
clause_body_location,
4438-
clause_location,
4439-
);
4432+
self.match_on_clause_variable(variable_type, variable_location, clause_location);
44404433
"Pattern match on variable"
44414434
}
44424435

@@ -4554,30 +4547,32 @@ where
45544547

45554548
fn match_on_clause_variable(
45564549
&mut self,
4557-
variable_name: &EcoString,
45584550
variable_type: Arc<Type>,
4559-
clause_body_location: SrcSpan,
4551+
variable_location: SrcSpan,
45604552
clause_location: SrcSpan,
45614553
) {
45624554
let Some(patterns) = self.type_to_destructure_patterns(variable_type.as_ref()) else {
45634555
return;
45644556
};
45654557

4566-
let body_code = code_at(self.module, clause_body_location);
4567-
45684558
let clause_range = self.edits.src_span_to_lsp_range(clause_location);
4569-
let nesting = " ".repeat(2 + clause_range.start.character as usize);
4559+
let nesting = " ".repeat(clause_range.start.character as usize);
4560+
4561+
let variable_start = (variable_location.start - clause_location.start) as usize;
4562+
let variable_end =
4563+
variable_start + (variable_location.end - variable_location.start) as usize;
45704564

4565+
let clause_code = code_at(self.module, clause_location);
45714566
let patterns = patterns
45724567
.iter()
4573-
.map(|p| format!(" {nesting}{p} -> {body_code}"))
4574-
.join("\n");
4575-
let pattern_matching = format!("case {variable_name} {{\n{patterns}\n{nesting}}}");
4568+
.map(|pattern| {
4569+
let mut clause_code = clause_code.to_string();
4570+
clause_code.replace_range(variable_start..variable_end, pattern);
4571+
clause_code
4572+
})
4573+
.join(&format!("\n{nesting}"));
45764574

4577-
self.edits.replace(
4578-
clause_body_location,
4579-
format!("\n{nesting}{pattern_matching}"),
4580-
);
4575+
self.edits.replace(clause_location, patterns);
45814576
}
45824577

45834578
/// Will produce a pattern that can be used on the left hand side of a let
@@ -4809,7 +4804,7 @@ where
48094804

48104805
fn visit_typed_assignment(&mut self, assignment: &'ast TypedAssignment) {
48114806
ast::visit::visit_typed_assignment(self, assignment);
4812-
if let Some((name, ref type_)) = self.pattern_variable_under_cursor {
4807+
if let Some((name, _, ref type_)) = self.pattern_variable_under_cursor {
48134808
self.selected_value = Some(PatternMatchedValue::LetVariable {
48144809
variable_name: name,
48154810
variable_type: type_.clone(),
@@ -4828,11 +4823,10 @@ where
48284823
}
48294824
}
48304825

4831-
if let Some((name, type_)) = self.pattern_variable_under_cursor.take() {
4826+
if let Some((_, variable_location, type_)) = self.pattern_variable_under_cursor.take() {
48324827
self.selected_value = Some(PatternMatchedValue::ClausePatternVariable {
4833-
variable_name: name,
48344828
variable_type: type_,
4835-
clause_body_location: clause.then.location(),
4829+
variable_location,
48364830
clause_location: clause.location(),
48374831
});
48384832
} else {
@@ -4888,7 +4882,7 @@ where
48884882
self.params.range,
48894883
self.edits.src_span_to_lsp_range(*location),
48904884
) {
4891-
self.pattern_variable_under_cursor = Some((name, type_.clone()));
4885+
self.pattern_variable_under_cursor = Some((name, *location, type_.clone()));
48924886
}
48934887
}
48944888

@@ -4907,14 +4901,14 @@ where
49074901
self.edits.src_span_to_lsp_range(*location),
49084902
)
49094903
{
4910-
self.pattern_variable_under_cursor = Some((name, type_::string()));
4904+
self.pattern_variable_under_cursor = Some((name, *location, type_::string()));
49114905
} else if let AssignName::Variable(name) = right_side_assignment
49124906
&& within(
49134907
self.params.range,
49144908
self.edits.src_span_to_lsp_range(*right_location),
49154909
)
49164910
{
4917-
self.pattern_variable_under_cursor = Some((name, type_::string()));
4911+
self.pattern_variable_under_cursor = Some((name, *right_location, type_::string()));
49184912
}
49194913
}
49204914
}

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6991,6 +6991,30 @@ fn maybe_wibble() { Ok(Wobble) }
69916991
);
69926992
}
69936993

6994+
#[test]
6995+
fn pattern_match_on_clause_variable_nested_pattern() {
6996+
assert_code_action!(
6997+
PATTERN_MATCH_ON_VARIABLE,
6998+
"
6999+
pub fn main() {
7000+
case maybe_wibble() {
7001+
Ok(Wobble(something)) -> 1
7002+
Error(_) -> 2
7003+
}
7004+
}
7005+
7006+
type Wibble {
7007+
Wobble(Wibble)
7008+
Woo
7009+
}
7010+
7011+
fn maybe_wibble() { Ok(Woo) }
7012+
7013+
",
7014+
find_position_of("something").to_selection()
7015+
);
7016+
}
7017+
69947018
#[test]
69957019
fn pattern_match_on_clause_variable_with_block_body() {
69967020
assert_code_action!(

compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__action__pattern_match_on_clause_variable.snap

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,8 @@ fn maybe_wibble() { Ok(Wobble) }
2525

2626
pub fn main() {
2727
case maybe_wibble() {
28-
Ok(something) ->
29-
case something {
30-
Wobble -> 1
31-
Woo -> 1
32-
}
28+
Ok(Wobble) -> 1
29+
Ok(Woo) -> 1
3330
Error(_) -> 2
3431
}
3532
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "\npub fn main() {\n case maybe_wibble() {\n Ok(Wobble(something)) -> 1\n Error(_) -> 2\n }\n}\n\ntype Wibble {\n Wobble(Wibble)\n Woo\n}\n\nfn maybe_wibble() { Ok(Woo) }\n\n"
4+
---
5+
----- BEFORE ACTION
6+
7+
pub fn main() {
8+
case maybe_wibble() {
9+
Ok(Wobble(something)) -> 1
10+
11+
Error(_) -> 2
12+
}
13+
}
14+
15+
type Wibble {
16+
Wobble(Wibble)
17+
Woo
18+
}
19+
20+
fn maybe_wibble() { Ok(Woo) }
21+
22+
23+
24+
----- AFTER ACTION
25+
26+
pub fn main() {
27+
case maybe_wibble() {
28+
Ok(Wobble(Wobble(wibble))) -> 1
29+
Ok(Wobble(Woo)) -> 1
30+
Error(_) -> 2
31+
}
32+
}
33+
34+
type Wibble {
35+
Wobble(Wibble)
36+
Woo
37+
}
38+
39+
fn maybe_wibble() { Ok(Woo) }

compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__action__pattern_match_on_clause_variable_with_block_body.snap

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,14 @@ fn maybe_wibble() { Ok(Wobble) }
2828

2929
pub fn main() {
3030
case maybe_wibble() {
31-
Ok(something) ->
32-
case something {
33-
Wobble -> {
31+
Ok(Wobble) -> {
3432
1
3533
2
3634
}
37-
Woo -> {
35+
Ok(Woo) -> {
3836
1
3937
2
4038
}
41-
}
4239
Error(_) -> 2
4340
}
4441
}

0 commit comments

Comments
 (0)