Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@

([Surya Rose](https://github.com/GearsDatapacks))

- When matching the wrong number of subjects, the compiler now pinpoints the
error location instead of marking the entire branch.
```
case wibble {
0, _ -> 1
^^^^ Expected 1 patterns, got 2
0 | -> 1
^ I was expecting a pattern after this
}
```
([fruno](https://github.com/fruno-bulax/))

- The performance of `==` and `!=` has been improved for single-variant custom
types when compiling to JavaScript. This was done by generating comparison
code specific to the custom type rather than using the generic equality check
Expand Down
15 changes: 11 additions & 4 deletions compiler-core/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1599,11 +1599,18 @@ where
match &patterns.first() {
Some(lead) => {
let mut alternative_patterns = vec![];
loop {
if self.maybe_one(&Token::Vbar).is_none() {
break;
while let Some((vbar_start, vbar_end)) = self.maybe_one(&Token::Vbar) {
let patterns = self.parse_patterns(PatternPosition::CaseClause)?;
if patterns.is_empty() {
return parse_error(
ParseErrorType::ExpectedPattern,
SrcSpan {
start: vbar_start,
end: vbar_end,
},
);
}
alternative_patterns.push(self.parse_patterns(PatternPosition::CaseClause)?);
alternative_patterns.push(patterns);
}
let guard = self.parse_case_clause_guard()?;
let (arr_s, arr_e) = self
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
source: compiler-core/src/parse/tests.rs
expression: "\nfn main() {\n case 1 {\n 1 | -> 1\n _ -> 1\n }\n}\n"
---
----- SOURCE CODE

fn main() {
case 1 {
1 | -> 1
_ -> 1
}
}


----- ERROR
error: Syntax error
┌─ /src/parse/error.gleam:4:9
4 │ 1 | -> 1
│ ^ I was expecting a pattern after this
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
source: compiler-core/src/parse/tests.rs
expression: "\nfn main() {\n case 1 {\n -> 1\n _ -> 2\n }\n}\n"
---
----- SOURCE CODE

fn main() {
case 1 {
-> 1
_ -> 2
}
}


----- ERROR
error: Syntax error
┌─ /src/parse/error.gleam:4:7
4 │ -> 1
│ ^^ I was not expecting this

Found `->`, expected one of:
- `}`
- a case clause
28 changes: 28 additions & 0 deletions compiler-core/src/parse/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,34 @@ fn main() {
);
}

#[test]
fn case_clause_no_subject() {
assert_module_error!(
"
fn main() {
case 1 {
-> 1
_ -> 2
}
}
"
);
}

#[test]
fn case_alternative_clause_no_subject() {
assert_module_error!(
"
fn main() {
case 1 {
1 | -> 1
_ -> 1
}
}
"
);
}

#[test]
fn use_invalid_assignments() {
assert_module_error!(
Expand Down
2 changes: 1 addition & 1 deletion compiler-core/src/type_/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2339,7 +2339,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
PatternPosition::CaseClause,
);

let typed_pattern = pattern_typer.infer_multi_pattern(pattern, subjects, location);
let typed_pattern = pattern_typer.infer_multi_pattern(pattern, subjects);

// Each case clause has one or more patterns that may match the
// subject in order for the clause to be selected, so we must type
Expand Down
12 changes: 9 additions & 3 deletions compiler-core/src/type_/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
location: &SrcSpan,
) -> Vec<TypedPattern> {
self.mode = PatternMode::Alternative(vec![]);
let typed_multi = self.infer_multi_pattern(multi_pattern, subjects, location);
let typed_multi = self.infer_multi_pattern(multi_pattern, subjects);

if self.error_encountered {
return typed_multi;
Expand Down Expand Up @@ -300,12 +300,18 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
&mut self,
multi_pattern: UntypedMultiPattern,
subjects: &[TypedExpr],
location: &SrcSpan,
) -> Vec<TypedPattern> {
// If there are N subjects the multi-pattern is expected to be N patterns
if subjects.len() != multi_pattern.len() {
let first = multi_pattern
.first()
.expect("multi-pattern to contain at least one pattern");
let last = multi_pattern
.last()
.expect("multi-pattern to contain at least one pattern");

self.error(Error::IncorrectNumClausePatterns {
location: *location,
location: first.location().merge(&last.location()),
expected: subjects.len(),
given: multi_pattern.len(),
});
Expand Down
5 changes: 5 additions & 0 deletions compiler-core/src/type_/tests/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ fn wrong_number_of_subjects() {
assert_error!("case 1 { _, _ -> 1 }");
}

#[test]
fn wrong_number_of_subjects_alternative_patterns() {
assert_error!("case 1 { _, _ | _ | _, _, _ -> 1 }");
}

#[test]
fn recursive_var() {
assert_error!("let id = fn(x) { x(x) } 1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ error: Incorrect number of patterns
┌─ /src/one/two.gleam:1:10
1 │ case 1 { _, _ -> 1 }
│ ^^^^^^^^^ Expected 1 patterns, got 2
│ ^^^^ Expected 1 patterns, got 2

This case expression has 1 subjects, but this pattern matches 2.
Each clause must have a pattern for every subject value.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
source: compiler-core/src/type_/tests/errors.rs
expression: "case 1 { _, _ | _ | _, _, _ -> 1 }"
---
----- SOURCE CODE
case 1 { _, _ | _ | _, _, _ -> 1 }

----- ERROR
error: Incorrect number of patterns
┌─ /src/one/two.gleam:1:10
1 │ case 1 { _, _ | _ | _, _, _ -> 1 }
│ ^^^^ Expected 1 patterns, got 2

This case expression has 1 subjects, but this pattern matches 2.
Each clause must have a pattern for every subject value.

error: Incorrect number of patterns
┌─ /src/one/two.gleam:1:21
1 │ case 1 { _, _ | _ | _, _, _ -> 1 }
│ ^^^^^^^ Expected 1 patterns, got 3

This case expression has 1 subjects, but this pattern matches 3.
Each clause must have a pattern for every subject value.
Loading