Skip to content

Commit b23e00f

Browse files
AaronC81lpil
authored andcommitted
Add relevant suggestion when a type annotation uses angle brackets
1 parent 4f5991c commit b23e00f

File tree

5 files changed

+94
-6
lines changed

5 files changed

+94
-6
lines changed

compiler-core/src/parse.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,7 +2564,7 @@ where
25642564
Ok((start, upname, arguments2, par_e, end))
25652565
} else if let Some((less_start, less_end)) = self.maybe_one(&Token::Less) {
25662566
Err(ParseError {
2567-
error: ParseErrorType::TypeAngleGenerics,
2567+
error: ParseErrorType::TypeDefinitionAngleGenerics,
25682568
location: SrcSpan {
25692569
start: less_start,
25702570
end: less_end,
@@ -2775,8 +2775,13 @@ where
27752775
arguments,
27762776
})))
27772777
} else if let Some((less_start, less_end)) = self.maybe_one(&Token::Less) {
2778+
let arguments = self.parse_types()?;
27782779
Err(ParseError {
2779-
error: ParseErrorType::TypeAngleGenerics,
2780+
error: ParseErrorType::TypeUsageAngleGenerics {
2781+
name,
2782+
module: module.map(|(module_name, _)| module_name),
2783+
arguments,
2784+
},
27802785
location: SrcSpan {
27812786
start: less_start,
27822787
end: less_end,

compiler-core/src/parse/error.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,14 @@ pub enum ParseErrorType {
118118
// When the use tries to define a constant inside a function
119119
ConstantInsideFunction,
120120
FunctionDefinitionAngleGenerics, // fn something<T>() { ... }
121-
TypeAngleGenerics, // let a: List<String> = []
121+
// let a: List<String> = []
122+
TypeUsageAngleGenerics {
123+
module: Option<EcoString>,
124+
name: EcoString,
125+
arguments: Vec<TypeAst>,
126+
},
127+
// type Something<T> {
128+
TypeDefinitionAngleGenerics,
122129
}
123130

124131
pub(crate) struct ParseErrorDetails {
@@ -669,7 +676,40 @@ See: https://tour.gleam.run/functions/generic-functions/"
669676
extra_labels: vec![],
670677
},
671678

672-
ParseErrorType::TypeAngleGenerics => ParseErrorDetails {
679+
ParseErrorType::TypeUsageAngleGenerics {
680+
module,
681+
name,
682+
arguments,
683+
} => {
684+
let type_arguments = arguments
685+
.iter()
686+
.map(|argument| {
687+
let mut argument_string = EcoString::new();
688+
argument.print(&mut argument_string);
689+
argument_string
690+
})
691+
.join(", ");
692+
let replacement_type = match module {
693+
Some(module) => format!("{module}.{name}({type_arguments})"),
694+
None => format!("{name}({type_arguments})"),
695+
};
696+
697+
ParseErrorDetails {
698+
text: format!(
699+
"\
700+
Type parameters use lowercase names and are surrounded by parentheses.
701+
702+
{replacement_type}
703+
704+
See: https://tour.gleam.run/data-types/generic-custom-types/"
705+
),
706+
hint: None,
707+
label_text: "I was expecting `(` here.".into(),
708+
extra_labels: vec![],
709+
}
710+
}
711+
712+
ParseErrorType::TypeDefinitionAngleGenerics => ParseErrorDetails {
673713
text: "\
674714
Type parameters use lowercase names and are surrounded by parentheses.
675715
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
source: compiler-core/src/parse/tests.rs
3+
expression: "let set: set.Set<Int> = set.new()"
4+
---
5+
----- SOURCE CODE
6+
let set: set.Set<Int> = set.new()
7+
8+
----- ERROR
9+
error: Syntax error
10+
┌─ /src/parse/error.gleam:1:17
11+
12+
1let set: set.Set<Int> = set.new()
13+
^ I was expecting `(` here.
14+
15+
Type parameters use lowercase names and are surrounded by parentheses.
16+
17+
set.Set(Int)
18+
19+
See: https://tour.gleam.run/data-types/generic-custom-types/
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
source: compiler-core/src/parse/tests.rs
3+
expression: "let list: List<Int, String> = []"
4+
---
5+
----- SOURCE CODE
6+
let list: List<Int, String> = []
7+
8+
----- ERROR
9+
error: Syntax error
10+
┌─ /src/parse/error.gleam:1:15
11+
12+
1let list: List<Int, String> = []
13+
^ I was expecting `(` here.
14+
15+
Type parameters use lowercase names and are surrounded by parentheses.
16+
17+
List(Int, String)
18+
19+
See: https://tour.gleam.run/data-types/generic-custom-types/

compiler-core/src/parse/tests.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,8 +1949,13 @@ fn function_definition_angle_generics_error() {
19491949
}
19501950

19511951
#[test]
1952-
fn type_angle_generics_usage_error() {
1953-
assert_error!("let list: List<Int> = []");
1952+
fn type_angle_generics_usage_without_module_error() {
1953+
assert_error!("let list: List<Int, String> = []");
1954+
}
1955+
1956+
#[test]
1957+
fn type_angle_generics_usage_with_module_error() {
1958+
assert_error!("let set: set.Set<Int> = set.new()");
19541959
}
19551960

19561961
#[test]

0 commit comments

Comments
 (0)