Skip to content

Commit c7ee6be

Browse files
GearsDatapackslpil
authored andcommitted
Improve error messages for constants defined in functions
1 parent e74cfe4 commit c7ee6be

File tree

5 files changed

+83
-1
lines changed

5 files changed

+83
-1
lines changed

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,32 @@
117117

118118
([Andrey Kozhev](https://github.com/ankddev))
119119

120+
- The compiler now provides an improved error message for when trying to define
121+
a constant inside a function. For example, the following code:
122+
123+
```gleam
124+
pub fn deep_thought() {
125+
const the_answer = 42
126+
the_answer
127+
}
128+
```
129+
130+
Will produce this error message:
131+
132+
```txt
133+
error: Syntax error
134+
┌─ /src/file.gleam:2:3
135+
136+
3 │ const the_answer = 43
137+
│ ^^^^^ Constants are not allowed inside functions
138+
139+
All variables are immutable in Gleam, so constants inside functions are not
140+
necessary.
141+
Hint: Either move this into the global scope or use `let` binding instead.
142+
```
143+
144+
([Surya Rose](https://github.com/GearsDatapacks))
145+
120146
### Build tool
121147

122148
- New projects are generated using OTP28 on GitHub Actions.

compiler-core/src/parse.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -803,11 +803,19 @@ where
803803
return parse_error(ParseErrorType::IfExpression, SrcSpan { start, end });
804804
}
805805

806-
// helpful error on possibly trying to group with ""
806+
// Helpful error on possibly trying to group with "(".
807807
Some((start, Token::LeftParen, _)) => {
808808
return parse_error(ParseErrorType::ExprLparStart, SrcSpan { start, end: start });
809809
}
810810

811+
// Helpful error when trying to define a constant inside a function.
812+
Some((start, Token::Const, end)) => {
813+
return parse_error(
814+
ParseErrorType::ConstantInsideFunction,
815+
SrcSpan { start, end },
816+
);
817+
}
818+
811819
// Boolean negation
812820
Some((start, Token::Bang, _end)) => {
813821
self.advance();

compiler-core/src/parse/error.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ pub enum ParseErrorType {
115115
/// This can happen when there's an empty block in a case clause guard.
116116
/// For example: `_ if a == {}`
117117
EmptyGuardBlock,
118+
// When the use tries to define a constant inside a function
119+
ConstantInsideFunction,
118120
}
119121

120122
pub(crate) struct ParseErrorDetails {
@@ -637,6 +639,18 @@ utf16_codepoint, utf32_codepoint, signed, unsigned, big, little, native, size, u
637639
label_text: "A clause guard block cannot be empty".into(),
638640
extra_labels: vec![],
639641
},
642+
643+
ParseErrorType::ConstantInsideFunction => ParseErrorDetails {
644+
text: wrap(
645+
"All variables are immutable in Gleam, so constants inside \
646+
functions are not necessary.",
647+
),
648+
hint: Some(
649+
"Either move this into the global scope or use `let` binding instead.".into(),
650+
),
651+
label_text: "Constants are not allowed inside functions".into(),
652+
extra_labels: vec![],
653+
},
640654
}
641655
}
642656
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
source: compiler-core/src/parse/tests.rs
3+
expression: "\npub fn main() {\n const x = 10\n x\n}\n"
4+
---
5+
----- SOURCE CODE
6+
7+
pub fn main() {
8+
const x = 10
9+
x
10+
}
11+
12+
13+
----- ERROR
14+
error: Syntax error
15+
┌─ /src/parse/error.gleam:3:3
16+
17+
3const x = 10
18+
^^^^^ Constants are not allowed inside functions
19+
20+
All variables are immutable in Gleam, so constants inside functions are not
21+
necessary.
22+
Hint: Either move this into the global scope or use `let` binding instead.

compiler-core/src/parse/tests.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,3 +1930,15 @@ fn case_guard_with_empty_block() {
19301930
}"
19311931
);
19321932
}
1933+
1934+
#[test]
1935+
fn constant_inside_function() {
1936+
assert_module_error!(
1937+
"
1938+
pub fn main() {
1939+
const x = 10
1940+
x
1941+
}
1942+
"
1943+
);
1944+
}

0 commit comments

Comments
 (0)