Skip to content

Commit 5eab96e

Browse files
GearsDatapackslpil
authored andcommitted
Localise type variables names when adding annotations
1 parent c1909f1 commit 5eab96e

7 files changed

+139
-41
lines changed

compiler-core/src/ast/visit.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,14 @@ pub fn visit_typed_function<'a, V>(v: &mut V, fun: &'a TypedFunction)
637637
where
638638
V: Visit<'a> + ?Sized,
639639
{
640+
for argument in fun.arguments.iter() {
641+
if let Some(annotation) = &argument.annotation {
642+
v.visit_type_ast(annotation);
643+
}
644+
}
645+
if let Some(annotation) = &fun.return_annotation {
646+
v.visit_type_ast(annotation);
647+
}
640648
for stmt in &fun.body {
641649
v.visit_typed_statement(stmt);
642650
}

compiler-core/src/language_server/code_action.rs

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,11 @@ impl<'ast> ast::visit::Visit<'ast> for AddAnnotations<'_> {
11701170
}
11711171

11721172
fn visit_typed_module_constant(&mut self, constant: &'ast TypedModuleConstant) {
1173+
// Since type variable names are local to definitions, any type variables
1174+
// in other parts of the module shouldn't affect what we print for the
1175+
// annotations of this constant.
1176+
self.printer.clear_type_variables();
1177+
11731178
let code_action_range = self.edits.src_span_to_lsp_range(constant.location);
11741179

11751180
// Only offer the code action if the cursor is over the statement
@@ -1189,6 +1194,14 @@ impl<'ast> ast::visit::Visit<'ast> for AddAnnotations<'_> {
11891194
}
11901195

11911196
fn visit_typed_function(&mut self, fun: &'ast ast::TypedFunction) {
1197+
self.printer.clear_type_variables();
1198+
1199+
// Since type variable names are local to definitions, any type variables
1200+
// in other parts of the module shouldn't affect what we print for the
1201+
// annotations of this functions. The only variables which cannot clash
1202+
// are ones defined in the signature of this function, which we register
1203+
// when we visit the parameters of this function below.
1204+
11921205
ast::visit::visit_typed_function(self, fun);
11931206

11941207
let code_action_range = self.edits.src_span_to_lsp_range(
@@ -1227,6 +1240,12 @@ impl<'ast> ast::visit::Visit<'ast> for AddAnnotations<'_> {
12271240
}
12281241
}
12291242

1243+
fn visit_type_ast_var(&mut self, _location: &'ast SrcSpan, name: &'ast EcoString) {
1244+
// Register this type variable so that we don't duplicate names when
1245+
// adding annotations.
1246+
self.printer.register_type_variable(name.clone());
1247+
}
1248+
12301249
fn visit_typed_expr_fn(
12311250
&mut self,
12321251
location: &'ast SrcSpan,
@@ -1420,19 +1439,6 @@ impl<'ast> ast::visit::Visit<'ast> for QualifiedToUnqualifiedImportFirstPass<'as
14201439
);
14211440
}
14221441

1423-
fn visit_typed_function(&mut self, fun: &'ast ast::TypedFunction) {
1424-
for arg in &fun.arguments {
1425-
if let Some(annotation) = &arg.annotation {
1426-
self.visit_type_ast(annotation);
1427-
}
1428-
}
1429-
1430-
if let Some(return_annotation) = &fun.return_annotation {
1431-
self.visit_type_ast(return_annotation);
1432-
}
1433-
ast::visit::visit_typed_function(self, fun);
1434-
}
1435-
14361442
fn visit_type_ast_constructor(
14371443
&mut self,
14381444
location: &'ast SrcSpan,
@@ -1659,19 +1665,6 @@ impl<'ast> ast::visit::Visit<'ast> for QualifiedToUnqualifiedImportSecondPass<'a
16591665
);
16601666
}
16611667

1662-
fn visit_typed_function(&mut self, fun: &'ast ast::TypedFunction) {
1663-
for arg in &fun.arguments {
1664-
if let Some(annotation) = &arg.annotation {
1665-
self.visit_type_ast(annotation);
1666-
}
1667-
}
1668-
1669-
if let Some(return_annotation) = &fun.return_annotation {
1670-
self.visit_type_ast(return_annotation);
1671-
}
1672-
ast::visit::visit_typed_function(self, fun);
1673-
}
1674-
16751668
fn visit_type_ast_constructor(
16761669
&mut self,
16771670
location: &'ast SrcSpan,
@@ -1904,18 +1897,6 @@ impl<'ast> ast::visit::Visit<'ast> for UnqualifiedToQualifiedImportFirstPass<'as
19041897
);
19051898
}
19061899

1907-
fn visit_typed_function(&mut self, fun: &'ast ast::TypedFunction) {
1908-
for arg in &fun.arguments {
1909-
if let Some(annotation) = &arg.annotation {
1910-
self.visit_type_ast(annotation);
1911-
}
1912-
}
1913-
1914-
if let Some(return_annotation) = &fun.return_annotation {
1915-
self.visit_type_ast(return_annotation);
1916-
}
1917-
ast::visit::visit_typed_function(self, fun);
1918-
}
19191900
fn visit_type_ast_constructor(
19201901
&mut self,
19211902
location: &'ast SrcSpan,

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9307,7 +9307,6 @@ fn collapse_nested_case_does_not_remove_labels() {
93079307
}
93089308
}
93099309
9310-
pub type Wibble {
93119310
Wibble(field: Int, field2: String)
93129311
Wobble
93139312
}
@@ -9328,7 +9327,6 @@ fn collapse_nested_case_does_not_remove_labels_with_shorthand_syntax() {
93289327
2 -> 4
93299328
_ -> -1
93309329
}
9331-
93329330
Wobble -> todo
93339331
}
93349332
}
@@ -9466,3 +9464,47 @@ fn collapse_nested_case_combines_inner_and_outer_guards_and_adds_parentheses_whe
94669464
find_position_of("first").to_selection()
94679465
);
94689466
}
9467+
9468+
// https://github.com/gleam-lang/gleam/issues/3786
9469+
#[test]
9470+
fn type_variables_from_other_functions_do_not_change_annotations() {
9471+
assert_code_action!(
9472+
ADD_ANNOTATIONS,
9473+
"
9474+
fn wibble(a: a, b: b, c: c) -> d { todo }
9475+
9476+
fn pair(a, b) {
9477+
#(a, b)
9478+
}
9479+
",
9480+
find_position_of("pair").to_selection()
9481+
);
9482+
}
9483+
9484+
#[test]
9485+
fn type_variables_from_other_functions_do_not_change_annotations_constant() {
9486+
assert_code_action!(
9487+
ADD_ANNOTATION,
9488+
"
9489+
fn wibble(a: a, b: b, c: c) -> d { todo }
9490+
9491+
const empty = []
9492+
",
9493+
find_position_of("empty").to_selection()
9494+
);
9495+
}
9496+
9497+
#[test]
9498+
fn type_variables_are_not_duplicated_when_adding_annotations() {
9499+
assert_code_action!(
9500+
ADD_ANNOTATIONS,
9501+
"
9502+
fn wibble(a: a, b: b, c: c) -> d { todo }
9503+
9504+
fn many_args(a, b, c, d: d, e: a, f, g) {
9505+
todo
9506+
}
9507+
",
9508+
find_position_of("many_args").to_selection()
9509+
);
9510+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nfn many_args(a, b, c, d: d, e: a, f, g) {\n todo\n}\n"
4+
---
5+
----- BEFORE ACTION
6+
7+
fn wibble(a: a, b: b, c: c) -> d { todo }
8+
9+
fn many_args(a, b, c, d: d, e: a, f, g) {
10+
11+
todo
12+
}
13+
14+
15+
----- AFTER ACTION
16+
17+
fn wibble(a: a, b: b, c: c) -> d { todo }
18+
19+
fn many_args(a: b, b: c, c: e, d: d, e: a, f: f, g: g) -> h {
20+
todo
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nfn pair(a, b) {\n #(a, b)\n}\n"
4+
---
5+
----- BEFORE ACTION
6+
7+
fn wibble(a: a, b: b, c: c) -> d { todo }
8+
9+
fn pair(a, b) {
10+
11+
#(a, b)
12+
}
13+
14+
15+
----- AFTER ACTION
16+
17+
fn wibble(a: a, b: b, c: c) -> d { todo }
18+
19+
fn pair(a: a, b: b) -> #(a, b) {
20+
#(a, b)
21+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "\nfn wibble(a: a, b: b, c: c) -> d { todo }\n\nconst empty = []\n"
4+
---
5+
----- BEFORE ACTION
6+
7+
fn wibble(a: a, b: b, c: c) -> d { todo }
8+
9+
const empty = []
10+
11+
12+
13+
----- AFTER ACTION
14+
15+
fn wibble(a: a, b: b, c: c) -> d { todo }
16+
17+
const empty: List(a) = []

compiler-core/src/type_/printer.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ pub enum PrintMode {
305305
/// names that types and modules have been aliased with in the current module.
306306
#[derive(Debug)]
307307
pub struct Printer<'a> {
308-
names: &'a Names,
308+
pub names: &'a Names,
309309
uid: u64,
310310

311311
/// Some type variables aren't bound to names, so when trying to print those,
@@ -333,6 +333,14 @@ impl<'a> Printer<'a> {
333333
}
334334
}
335335

336+
pub fn clear_type_variables(&mut self) {
337+
self.printed_type_variable_names.clear();
338+
}
339+
340+
pub fn register_type_variable(&mut self, name: EcoString) {
341+
_ = self.printed_type_variable_names.insert(name);
342+
}
343+
336344
pub fn print_type(&mut self, type_: &Type) -> EcoString {
337345
let mut buffer = EcoString::new();
338346
self.print(type_, &mut buffer, PrintMode::Normal);

0 commit comments

Comments
 (0)