Skip to content

Commit a23d0ca

Browse files
AaronC81lpil
authored andcommitted
Add relevant suggestion when a type definition uses angle brackets
1 parent b23e00f commit a23d0ca

6 files changed

+125
-23
lines changed

compiler-core/src/parse.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2563,8 +2563,29 @@ where
25632563
.collect();
25642564
Ok((start, upname, arguments2, par_e, end))
25652565
} else if let Some((less_start, less_end)) = self.maybe_one(&Token::Less) {
2566+
let mut arguments = Parser::series_of(
2567+
self,
2568+
&|p|
2569+
// Permit either names (`a`) or upnames (`A`) in this error-handling mode,
2570+
// as upnames are common in other languages. Convert to lowercase so the
2571+
// example is correct whichever was used.
2572+
Ok(Parser::maybe_name(p)
2573+
.or_else(|| Parser::maybe_upname(p))
2574+
.map(|(_, name, _)| name.to_lowercase())),
2575+
Some(&Token::Comma),
2576+
)?;
2577+
2578+
// If no type arguments were parsed, fall back to a dummy type argument as an example,
2579+
// because `Type()` would be invalid
2580+
if arguments.is_empty() {
2581+
arguments = vec!["value".into()];
2582+
}
2583+
25662584
Err(ParseError {
2567-
error: ParseErrorType::TypeDefinitionAngleGenerics,
2585+
error: ParseErrorType::TypeDefinitionAngleGenerics {
2586+
name: upname,
2587+
arguments: arguments,
2588+
},
25682589
location: SrcSpan {
25692590
start: less_start,
25702591
end: less_end,

compiler-core/src/parse/error.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ pub enum ParseErrorType {
125125
arguments: Vec<TypeAst>,
126126
},
127127
// type Something<T> {
128-
TypeDefinitionAngleGenerics,
128+
TypeDefinitionAngleGenerics {
129+
name: EcoString,
130+
arguments: Vec<EcoString>,
131+
},
129132
}
130133

131134
pub(crate) struct ParseErrorDetails {
@@ -709,18 +712,23 @@ See: https://tour.gleam.run/data-types/generic-custom-types/"
709712
}
710713
}
711714

712-
ParseErrorType::TypeDefinitionAngleGenerics => ParseErrorDetails {
713-
text: "\
715+
ParseErrorType::TypeDefinitionAngleGenerics { name, arguments } => {
716+
let comma_separated_arguments = arguments.join(", ");
717+
718+
ParseErrorDetails {
719+
text: format!(
720+
"\
714721
Type parameters use lowercase names and are surrounded by parentheses.
715722
716-
List(String)
717-
Result(Int, Error)
723+
type {name}({comma_separated_arguments}) {{
718724
719-
See: https://tour.gleam.run/data-types/generic-custom-types/".into(),
720-
hint: None,
721-
label_text: "I was expecting `(` here.".into(),
722-
extra_labels: vec![],
723-
},
725+
See: https://tour.gleam.run/data-types/generic-custom-types/"
726+
),
727+
hint: None,
728+
label_text: "I was expecting `(` here.".into(),
729+
extra_labels: vec![],
730+
}
731+
}
724732
}
725733
}
726734
}
Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
---
22
source: compiler-core/src/parse/tests.rs
3-
expression: "\ntype Maybe<A> {\n Some(A)\n None\n}\n"
3+
expression: "\ntype Either<a, b> {\n This(a)\n That(b)\n}\n"
44
---
55
----- SOURCE CODE
66

7-
type Maybe<A> {
8-
Some(A)
9-
None
7+
type Either<a, b> {
8+
This(a)
9+
That(b)
1010
}
1111

1212

1313
----- ERROR
1414
error: Syntax error
15-
┌─ /src/parse/error.gleam:2:11
15+
┌─ /src/parse/error.gleam:2:12
1616
17-
2type Maybe<A> {
18-
│ ^ I was expecting `(` here.
17+
2type Either<a, b> {
18+
^ I was expecting `(` here.
1919

2020
Type parameters use lowercase names and are surrounded by parentheses.
2121

22-
List(String)
23-
Result(Int, Error)
22+
type Either(a, b) {
2423

2524
See: https://tour.gleam.run/data-types/generic-custom-types/
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
source: compiler-core/src/parse/tests.rs
3+
expression: "\ntype Either<type A, type B> {\n This(A)\n That(B)\n}\n"
4+
---
5+
----- SOURCE CODE
6+
7+
type Either<type A, type B> {
8+
This(A)
9+
That(B)
10+
}
11+
12+
13+
----- ERROR
14+
error: Syntax error
15+
┌─ /src/parse/error.gleam:2:12
16+
17+
2type Either<type A, type B> {
18+
│ ^ I was expecting `(` here.
19+
20+
Type parameters use lowercase names and are surrounded by parentheses.
21+
22+
type Either(value) {
23+
24+
See: https://tour.gleam.run/data-types/generic-custom-types/
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
source: compiler-core/src/parse/tests.rs
3+
expression: "\ntype Either<A, B> {\n This(A)\n That(B)\n}\n"
4+
---
5+
----- SOURCE CODE
6+
7+
type Either<A, B> {
8+
This(A)
9+
That(B)
10+
}
11+
12+
13+
----- ERROR
14+
error: Syntax error
15+
┌─ /src/parse/error.gleam:2:12
16+
17+
2type Either<A, B> {
18+
│ ^ I was expecting `(` here.
19+
20+
Type parameters use lowercase names and are surrounded by parentheses.
21+
22+
type Either(a, b) {
23+
24+
See: https://tour.gleam.run/data-types/generic-custom-types/

compiler-core/src/parse/tests.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,9 +1962,35 @@ fn type_angle_generics_usage_with_module_error() {
19621962
fn type_angle_generics_definition_error() {
19631963
assert_module_error!(
19641964
r#"
1965-
type Maybe<A> {
1966-
Some(A)
1967-
None
1965+
type Either<a, b> {
1966+
This(a)
1967+
That(b)
1968+
}
1969+
"#
1970+
);
1971+
}
1972+
1973+
#[test]
1974+
fn type_angle_generics_definition_with_upname_error() {
1975+
assert_module_error!(
1976+
r#"
1977+
type Either<A, B> {
1978+
This(A)
1979+
That(B)
1980+
}
1981+
"#
1982+
);
1983+
}
1984+
1985+
#[test]
1986+
fn type_angle_generics_definition_error_fallback() {
1987+
// Example of a more incorrect syntax, where Gleam doesn't make a suggestion.
1988+
// In this case, an example type argument is used instead.
1989+
assert_module_error!(
1990+
r#"
1991+
type Either<type A, type B> {
1992+
This(A)
1993+
That(B)
19681994
}
19691995
"#
19701996
);

0 commit comments

Comments
 (0)