From 56e2011744172efd2193a2549bb8993e15406b25 Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Fri, 10 Apr 2026 12:21:56 +0200 Subject: [PATCH 01/10] Add match patterns for list literals --- .../jvm/src/test/scala/effekt/ParserTests.scala | 17 +++++++++++++++++ .../shared/src/main/scala/effekt/Parser.scala | 9 +++++++++ 2 files changed, 26 insertions(+) diff --git a/effekt/jvm/src/test/scala/effekt/ParserTests.scala b/effekt/jvm/src/test/scala/effekt/ParserTests.scala index bb0527258..3ee74c1a9 100644 --- a/effekt/jvm/src/test/scala/effekt/ParserTests.scala +++ b/effekt/jvm/src/test/scala/effekt/ParserTests.scala @@ -623,6 +623,23 @@ class ParserTests extends munit.FunSuite { parseMatchPattern("_"), IgnorePattern(Span.missing)) parseMatchPattern("Cons(x, Cons(x, Nil()))") + parseMatchPattern("[]") + parseMatchPattern("[1]") + parseMatchPattern("[_, 2, (3, 4)]") + parseMatchPattern("[[1, 2], [3, [4, (6, [7, 8])]]]") + + { + def cons(head: MatchPattern, tail: MatchPattern) = + TagPattern(IdRef(Nil, "Cons", Span.missing), List(head, tail), Span.missing) + def nil = TagPattern(IdRef(Nil, "Nil", Span.missing), Nil, Span.missing) + def lit(l: Int) = + LiteralPattern(Literal(l, symbols.builtins.TInt, Span.missing), Span.missing) + + assertEqualModuloSpans( + parseMatchPattern("[1, [2, 3, 4], [5]]"), + cons(lit(1), cons(cons(lit(2), cons(lit(3), cons(lit(4), nil))), cons(cons(lit(5), nil), nil))) + ) + } { val (source, pos) = diff --git a/effekt/shared/src/main/scala/effekt/Parser.scala b/effekt/shared/src/main/scala/effekt/Parser.scala index d73a164ed..35c1ef5eb 100644 --- a/effekt/shared/src/main/scala/effekt/Parser.scala +++ b/effekt/shared/src/main/scala/effekt/Parser.scala @@ -1018,8 +1018,17 @@ class Parser(tokens: Seq[Token], source: Source) { case Many(p :: Nil , _) => fail("Pattern matching on tuples requires more than one element") case Many(ps, _) => TagPattern(IdRef(List("effekt"), s"Tuple${ps.size}", span().synthesized), ps, span()) } + case `[` => some(matchPattern, `[`, `,`, `[`) match { + case Many(ps, _) => ps.foldRight(NilPattern)(ConsPattern) + } case k => fail("pattern", k) } + + private def NilPattern: MatchPattern = + TagPattern(IdRef(Nil, "Nil", span().synthesized), Nil, span()) + + private def ConsPattern(head: MatchPattern, tail: MatchPattern): MatchPattern = + TagPattern(IdRef(Nil, "Cons", span().synthesized), List(head, tail), span()) def matchExpr(scrutinee: Term): Term = val clauses = `match` ~> braces { manyWhile(matchClause(), `case`) } From b016abd04bc814a0e0703e2ae8a0bd1038bcfc87 Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Fri, 10 Apr 2026 12:22:45 +0200 Subject: [PATCH 02/10] Add metals stuff to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 3688df3e6..c91927634 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ build/ out/ project/target/ +project/project target/ drafts/ node_modules/ @@ -12,6 +13,7 @@ licenses/ .bsp/ bin .metals/ +project/metals.sbt .vscode/ .bloop/ *.tgz From cc662ecdfb3387c8fed43da829a35a126e21c8b1 Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Fri, 10 Apr 2026 13:33:10 +0200 Subject: [PATCH 03/10] Use manyTrailing and create invalid example --- effekt/shared/src/main/scala/effekt/Parser.scala | 4 +--- examples/neg/parsing/invalid_lit_list_pattern.check | 3 +++ examples/neg/parsing/invalid_lit_list_pattern.effekt | 5 +++++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 examples/neg/parsing/invalid_lit_list_pattern.check create mode 100644 examples/neg/parsing/invalid_lit_list_pattern.effekt diff --git a/effekt/shared/src/main/scala/effekt/Parser.scala b/effekt/shared/src/main/scala/effekt/Parser.scala index 35c1ef5eb..e4d684639 100644 --- a/effekt/shared/src/main/scala/effekt/Parser.scala +++ b/effekt/shared/src/main/scala/effekt/Parser.scala @@ -1018,9 +1018,7 @@ class Parser(tokens: Seq[Token], source: Source) { case Many(p :: Nil , _) => fail("Pattern matching on tuples requires more than one element") case Many(ps, _) => TagPattern(IdRef(List("effekt"), s"Tuple${ps.size}", span().synthesized), ps, span()) } - case `[` => some(matchPattern, `[`, `,`, `[`) match { - case Many(ps, _) => ps.foldRight(NilPattern)(ConsPattern) - } + case `[` => manyTrailing(matchPattern, `[`, `,`, `]`).foldRight(NilPattern)(ConsPattern) case k => fail("pattern", k) } diff --git a/examples/neg/parsing/invalid_lit_list_pattern.check b/examples/neg/parsing/invalid_lit_list_pattern.check new file mode 100644 index 000000000..c6ccc9b1b --- /dev/null +++ b/examples/neg/parsing/invalid_lit_list_pattern.check @@ -0,0 +1,3 @@ +[error] examples/neg/parsing/invalid_lit_list_pattern.effekt:3:14: Expected ] but got ) +case [1, [2, 3)] => () + ^ \ No newline at end of file diff --git a/examples/neg/parsing/invalid_lit_list_pattern.effekt b/examples/neg/parsing/invalid_lit_list_pattern.effekt new file mode 100644 index 000000000..96a0d0e27 --- /dev/null +++ b/examples/neg/parsing/invalid_lit_list_pattern.effekt @@ -0,0 +1,5 @@ +val _ = [] match { + case [] => () + case [1, [2, 3)] => () + case _ => () +} \ No newline at end of file From 6ba4332b1aaef33cc14a2d469581d4871dbb18bb Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Fri, 10 Apr 2026 13:42:55 +0200 Subject: [PATCH 04/10] Fix expected error message --- examples/neg/parsing/invalid_lit_list_pattern.check | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/neg/parsing/invalid_lit_list_pattern.check b/examples/neg/parsing/invalid_lit_list_pattern.check index c6ccc9b1b..8ab12e53f 100644 --- a/examples/neg/parsing/invalid_lit_list_pattern.check +++ b/examples/neg/parsing/invalid_lit_list_pattern.check @@ -1,3 +1,3 @@ -[error] examples/neg/parsing/invalid_lit_list_pattern.effekt:3:14: Expected ] but got ) -case [1, [2, 3)] => () - ^ \ No newline at end of file +[error] examples/neg/parsing/invalid_lit_list_pattern.effekt:3:17: Expected ] but got ) + case [1, [2, 3)] => () + ^ \ No newline at end of file From a0e7eaf7f156cca07a3779df4ca757be07d6b72c Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Fri, 10 Apr 2026 15:33:15 +0200 Subject: [PATCH 05/10] Broken Progress --- .../shared/src/main/scala/effekt/Parser.scala | 51 +++++++++++++++---- .../src/main/scala/effekt/source/Tree.scala | 6 +++ 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/effekt/shared/src/main/scala/effekt/Parser.scala b/effekt/shared/src/main/scala/effekt/Parser.scala index e4d684639..47cbbf3d7 100644 --- a/effekt/shared/src/main/scala/effekt/Parser.scala +++ b/effekt/shared/src/main/scala/effekt/Parser.scala @@ -1005,22 +1005,33 @@ class Parser(tokens: Seq[Token], source: Source) { nonterminal: peek.kind match { case `__` => skip(); IgnorePattern(span()) - case _ if isVariable => - idRef() match { - case id if peek(`(`) => TagPattern(id, many(matchPattern, `(`, `,`, `)`).unspan, span()) - case IdRef(Nil, name, span) => AnyPattern(IdDef(name, span), span) - case IdRef(_, name, _) => fail("Cannot use qualified names to bind a pattern variable") - } - case _ if isVariable => - AnyPattern(idDef(), span()) + case _ if isVariable => idRef() match { + case id if peek(`(`) => TagPattern(id, many(matchPattern, `(`, `,`, `)`).unspan, span()) + case IdRef(Nil, name, span) => AnyPattern(IdDef(name, span), span) + case IdRef(_, name, _) => fail("Cannot use qualified names to bind a pattern variable") + } case _ if isLiteral => LiteralPattern(literal(), span()) case `(` => some(matchPattern, `(`, `,`, `)`) match { case Many(p :: Nil , _) => fail("Pattern matching on tuples requires more than one element") case Many(ps, _) => TagPattern(IdRef(List("effekt"), s"Tuple${ps.size}", span().synthesized), ps, span()) } - case `[` => manyTrailing(matchPattern, `[`, `,`, `]`).foldRight(NilPattern)(ConsPattern) + case `[` => listPattern() case k => fail("pattern", k) } + + private def listPattern(): MatchPattern = { + val (ps, last) = manyTrailingLastSpecial(matchPattern, listMatchPattern, `[`, `,`, `]`) + val last = ps.last match { + case + } + } + + private def listMatchPattern(): MatchPattern = peek.kind match { + case `..` => + consume(`..`) + idDef() match { case id: IdDef => TailPattern(id, id.span) } + case _ => matchPattern() + } private def NilPattern: MatchPattern = TagPattern(IdRef(Nil, "Nil", span().synthesized), Nil, span()) @@ -1920,6 +1931,28 @@ class Parser(tokens: Seq[Token], source: Source) { components.toList } + inline def manyTrailingLastSpecial[T](p: () => T, last: () => T, before: TokenKind, sep: TokenKind, after: TokenKind): (List[T], Option[T]) = + consume(before) + if (peek(after)) { + consume(after) + (Nil, None) + } else if (peek(sep)) { + consume(sep) + consume(after) + (Nil, None) + } else { + val components: ListBuffer[T] = ListBuffer.empty + components += p() + while (peek(sep)) { + consume(sep) + + if (!peek(after)) { + components += p() + } + } + consume(after) + (components.init.toList, Some(components.last)) + } // Positions diff --git a/effekt/shared/src/main/scala/effekt/source/Tree.scala b/effekt/shared/src/main/scala/effekt/source/Tree.scala index 45486e0aa..15393f25f 100644 --- a/effekt/shared/src/main/scala/effekt/source/Tree.scala +++ b/effekt/shared/src/main/scala/effekt/source/Tree.scala @@ -684,6 +684,12 @@ enum MatchPattern extends Tree { * Currently should *only* occur in lambda-cases & `with` statements during parsing */ case MultiPattern(patterns: List[MatchPattern], span: Span) extends MatchPattern + + /** + * Matchin the tail of a list + * case [a, ..b] => ... + */ + case TailPattern(id: IdDef, span: Span) extends MatchPattern, Definition } export MatchPattern.* From 6cfb351312c19606c53295c19347d760d5a62aee Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Sun, 12 Apr 2026 09:50:41 +0200 Subject: [PATCH 06/10] Add splat syntax --- .../src/test/scala/effekt/ParserTests.scala | 1 + .../shared/src/main/scala/effekt/Parser.scala | 54 ++++++++----------- .../src/main/scala/effekt/source/Tree.scala | 6 --- ...n.check => invalid-lit-list-pattern.check} | 2 +- ...effekt => invalid-lit-list-pattern.effekt} | 0 .../neg/parsing/tail-pattern-too-early.check | 3 ++ .../neg/parsing/tail-pattern-too-early.effekt | 3 ++ .../pos/patternmatching/matching-list.check | 9 ++++ .../pos/patternmatching/matching-list.effekt | 27 ++++++++++ 9 files changed, 67 insertions(+), 38 deletions(-) rename examples/neg/parsing/{invalid_lit_list_pattern.check => invalid-lit-list-pattern.check} (50%) rename examples/neg/parsing/{invalid_lit_list_pattern.effekt => invalid-lit-list-pattern.effekt} (100%) create mode 100644 examples/neg/parsing/tail-pattern-too-early.check create mode 100644 examples/neg/parsing/tail-pattern-too-early.effekt create mode 100644 examples/pos/patternmatching/matching-list.check create mode 100644 examples/pos/patternmatching/matching-list.effekt diff --git a/effekt/jvm/src/test/scala/effekt/ParserTests.scala b/effekt/jvm/src/test/scala/effekt/ParserTests.scala index 3ee74c1a9..174c7b1b8 100644 --- a/effekt/jvm/src/test/scala/effekt/ParserTests.scala +++ b/effekt/jvm/src/test/scala/effekt/ParserTests.scala @@ -627,6 +627,7 @@ class ParserTests extends munit.FunSuite { parseMatchPattern("[1]") parseMatchPattern("[_, 2, (3, 4)]") parseMatchPattern("[[1, 2], [3, [4, (6, [7, 8])]]]") + parseMatchPattern("[x, [..y], [z, ..v]]") { def cons(head: MatchPattern, tail: MatchPattern) = diff --git a/effekt/shared/src/main/scala/effekt/Parser.scala b/effekt/shared/src/main/scala/effekt/Parser.scala index 47cbbf3d7..4d57f9a9b 100644 --- a/effekt/shared/src/main/scala/effekt/Parser.scala +++ b/effekt/shared/src/main/scala/effekt/Parser.scala @@ -1020,17 +1020,31 @@ class Parser(tokens: Seq[Token], source: Source) { } private def listPattern(): MatchPattern = { - val (ps, last) = manyTrailingLastSpecial(matchPattern, listMatchPattern, `[`, `,`, `]`) - val last = ps.last match { - case - } - } + val components: ListBuffer[MatchPattern] = ListBuffer.empty + var lastPattern = NilPattern - private def listMatchPattern(): MatchPattern = peek.kind match { - case `..` => + consume(`[`) + peek.kind match { + case `]` | `,` | `..` => ; + case _ => components += matchPattern() + } + + while (peek(`,`)) { + consume(`,`) + if(!peek(`]`) && !peek(`..`)) { + components += matchPattern() + } + } + if (peek(`..`)) { consume(`..`) - idDef() match { case id: IdDef => TailPattern(id, id.span) } - case _ => matchPattern() + lastPattern = peek.kind match { + case `]` => IgnorePattern(span()) + case _ => idDef() match { case id: IdDef => AnyPattern(id, id.span) } + } + } + consume(`]`) + + components.toList.foldRight(lastPattern)(ConsPattern) } private def NilPattern: MatchPattern = @@ -1931,28 +1945,6 @@ class Parser(tokens: Seq[Token], source: Source) { components.toList } - inline def manyTrailingLastSpecial[T](p: () => T, last: () => T, before: TokenKind, sep: TokenKind, after: TokenKind): (List[T], Option[T]) = - consume(before) - if (peek(after)) { - consume(after) - (Nil, None) - } else if (peek(sep)) { - consume(sep) - consume(after) - (Nil, None) - } else { - val components: ListBuffer[T] = ListBuffer.empty - components += p() - while (peek(sep)) { - consume(sep) - - if (!peek(after)) { - components += p() - } - } - consume(after) - (components.init.toList, Some(components.last)) - } // Positions diff --git a/effekt/shared/src/main/scala/effekt/source/Tree.scala b/effekt/shared/src/main/scala/effekt/source/Tree.scala index 15393f25f..45486e0aa 100644 --- a/effekt/shared/src/main/scala/effekt/source/Tree.scala +++ b/effekt/shared/src/main/scala/effekt/source/Tree.scala @@ -684,12 +684,6 @@ enum MatchPattern extends Tree { * Currently should *only* occur in lambda-cases & `with` statements during parsing */ case MultiPattern(patterns: List[MatchPattern], span: Span) extends MatchPattern - - /** - * Matchin the tail of a list - * case [a, ..b] => ... - */ - case TailPattern(id: IdDef, span: Span) extends MatchPattern, Definition } export MatchPattern.* diff --git a/examples/neg/parsing/invalid_lit_list_pattern.check b/examples/neg/parsing/invalid-lit-list-pattern.check similarity index 50% rename from examples/neg/parsing/invalid_lit_list_pattern.check rename to examples/neg/parsing/invalid-lit-list-pattern.check index 8ab12e53f..6ebb122d6 100644 --- a/examples/neg/parsing/invalid_lit_list_pattern.check +++ b/examples/neg/parsing/invalid-lit-list-pattern.check @@ -1,3 +1,3 @@ -[error] examples/neg/parsing/invalid_lit_list_pattern.effekt:3:17: Expected ] but got ) +[error] examples/neg/parsing/invalid-lit-list-pattern.effekt:3:17: Expected ] but got ) case [1, [2, 3)] => () ^ \ No newline at end of file diff --git a/examples/neg/parsing/invalid_lit_list_pattern.effekt b/examples/neg/parsing/invalid-lit-list-pattern.effekt similarity index 100% rename from examples/neg/parsing/invalid_lit_list_pattern.effekt rename to examples/neg/parsing/invalid-lit-list-pattern.effekt diff --git a/examples/neg/parsing/tail-pattern-too-early.check b/examples/neg/parsing/tail-pattern-too-early.check new file mode 100644 index 000000000..5eb6cc5bf --- /dev/null +++ b/examples/neg/parsing/tail-pattern-too-early.check @@ -0,0 +1,3 @@ +[error] examples/neg/parsing/tail-pattern-too-early.effekt:2:12: Expected ] but got , + case [..x, y] => 3 + ^ \ No newline at end of file diff --git a/examples/neg/parsing/tail-pattern-too-early.effekt b/examples/neg/parsing/tail-pattern-too-early.effekt new file mode 100644 index 000000000..bd2385455 --- /dev/null +++ b/examples/neg/parsing/tail-pattern-too-early.effekt @@ -0,0 +1,3 @@ +val _ = [1, 2] match { + case [..x, y] => 3 +} \ No newline at end of file diff --git a/examples/pos/patternmatching/matching-list.check b/examples/pos/patternmatching/matching-list.check new file mode 100644 index 000000000..0285ad8fe --- /dev/null +++ b/examples/pos/patternmatching/matching-list.check @@ -0,0 +1,9 @@ +hello +4 +Cons(5, Cons(6, Nil())) +42 +Cons(1, Nil()) +--- +world +world +helloSome(4)5 \ No newline at end of file diff --git a/examples/pos/patternmatching/matching-list.effekt b/examples/pos/patternmatching/matching-list.effekt new file mode 100644 index 000000000..65f817df3 --- /dev/null +++ b/examples/pos/patternmatching/matching-list.effekt @@ -0,0 +1,27 @@ +def ex1(lst: List[Int]) = lst match { + case [1, 2] => "hello" + case [42, x, 2] => x.show + case [3, 4, ..y] => y.show + case [_, ..] => "42" + case [..x] => x.show +} + +def ex2(lst: List[Option[Int]]) = { + if(lst is [head, Some(x)]) { + "hello" ++ head.show ++ x.show + } else { + "world" + } +} + +def main() = { + println(ex1([1, 2])) + println(ex1([42, 4, 2])) + println(ex1([3, 4, 5, 6])) + println(ex1([1, 2])) + println(ex1([1])) + println("---") + println(ex2([Some(2), None()])) + println(ex2([Some(2), Some(3), Some(3)])) + println(ex2([Some(4), Some(5)])) +} \ No newline at end of file From 87e5678f6f18bd15500a5bae83d56a9dcb253f25 Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Wed, 15 Apr 2026 18:30:08 +0200 Subject: [PATCH 07/10] Add pos tests --- .../pos/patternmatching/matching-list.check | 8 ++++++-- .../pos/patternmatching/matching-list.effekt | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/examples/pos/patternmatching/matching-list.check b/examples/pos/patternmatching/matching-list.check index 0285ad8fe..b66390ba4 100644 --- a/examples/pos/patternmatching/matching-list.check +++ b/examples/pos/patternmatching/matching-list.check @@ -1,9 +1,13 @@ hello 4 Cons(5, Cons(6, Nil())) -42 +don't care Cons(1, Nil()) --- world world -helloSome(4)5 \ No newline at end of file +helloSome(4)5 +--- +42 +--- +6 diff --git a/examples/pos/patternmatching/matching-list.effekt b/examples/pos/patternmatching/matching-list.effekt index 65f817df3..55fcaee3d 100644 --- a/examples/pos/patternmatching/matching-list.effekt +++ b/examples/pos/patternmatching/matching-list.effekt @@ -2,7 +2,7 @@ def ex1(lst: List[Int]) = lst match { case [1, 2] => "hello" case [42, x, 2] => x.show case [3, 4, ..y] => y.show - case [_, ..] => "42" + case [_, ..] => "don't care" case [..x] => x.show } @@ -14,6 +14,18 @@ def ex2(lst: List[Option[Int]]) = { } } +def ex3(lst: List[List[Int]]) = { + val [fst, [_, x]] = lst else panic("Ohno") + x +} + +def foo(lst: List[Int]) { f: List[Int] => Unit } = f(lst) + +def ex4(lst: List[Int]) = foo(lst) { + case [a, b, c] => println(a + b + c) + case _ => panic("Ohno") +} + def main() = { println(ex1([1, 2])) println(ex1([42, 4, 2])) @@ -24,4 +36,8 @@ def main() = { println(ex2([Some(2), None()])) println(ex2([Some(2), Some(3), Some(3)])) println(ex2([Some(4), Some(5)])) + println("---") + println(ex3([[3], [2, 42]])) + println("---") + println(ex4([1, 2, 3])) } \ No newline at end of file From 6c3ce66e700b85252e8390dcbf43ea60e1cbf928 Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Wed, 15 Apr 2026 18:35:18 +0200 Subject: [PATCH 08/10] Fix pos test output --- examples/pos/patternmatching/matching-list.check | 2 +- examples/pos/patternmatching/matching-list.effekt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/pos/patternmatching/matching-list.check b/examples/pos/patternmatching/matching-list.check index b66390ba4..e4cdce226 100644 --- a/examples/pos/patternmatching/matching-list.check +++ b/examples/pos/patternmatching/matching-list.check @@ -2,7 +2,7 @@ hello 4 Cons(5, Cons(6, Nil())) don't care -Cons(1, Nil()) +Nil() --- world world diff --git a/examples/pos/patternmatching/matching-list.effekt b/examples/pos/patternmatching/matching-list.effekt index 55fcaee3d..4f232a7d2 100644 --- a/examples/pos/patternmatching/matching-list.effekt +++ b/examples/pos/patternmatching/matching-list.effekt @@ -30,8 +30,8 @@ def main() = { println(ex1([1, 2])) println(ex1([42, 4, 2])) println(ex1([3, 4, 5, 6])) - println(ex1([1, 2])) - println(ex1([1])) + println(ex1([44, 444])) + println(ex1([])) println("---") println(ex2([Some(2), None()])) println(ex2([Some(2), Some(3), Some(3)])) From de8a0bafdfb9aefcdd8a0bb4ae931982c8529589 Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Wed, 15 Apr 2026 18:45:37 +0200 Subject: [PATCH 09/10] shorten manyTrailing Definition --- .../shared/src/main/scala/effekt/Parser.scala | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/effekt/shared/src/main/scala/effekt/Parser.scala b/effekt/shared/src/main/scala/effekt/Parser.scala index 4d57f9a9b..be717a8ef 100644 --- a/effekt/shared/src/main/scala/effekt/Parser.scala +++ b/effekt/shared/src/main/scala/effekt/Parser.scala @@ -1923,27 +1923,20 @@ class Parser(tokens: Seq[Token], source: Source) { inline def manyTrailing[T](p: () => T, before: TokenKind, sep: TokenKind, after: TokenKind): List[T] = + val components: ListBuffer[T] = ListBuffer.empty consume(before) - if (peek(after)) { - consume(after) - Nil - } else if (peek(sep)) { - consume(sep) - consume(after) - Nil - } else { - val components: ListBuffer[T] = ListBuffer.empty + if (!peek(after) && !peek(sep)) { components += p() - while (peek(sep)) { - consume(sep) - - if (!peek(after)) { - components += p() - } + } + + while (peek(sep)) { + consume(sep) + if(!peek(after)) { + components += p() } - consume(after) - components.toList } + consume(after) + components.toList // Positions From 976c97faf64c85adffc2a366af5f6d516dab415b Mon Sep 17 00:00:00 2001 From: Martin Ilgner Date: Wed, 15 Apr 2026 18:51:22 +0200 Subject: [PATCH 10/10] Fix really dumb mistake --- examples/pos/patternmatching/matching-list.effekt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/pos/patternmatching/matching-list.effekt b/examples/pos/patternmatching/matching-list.effekt index 4f232a7d2..712cb6a00 100644 --- a/examples/pos/patternmatching/matching-list.effekt +++ b/examples/pos/patternmatching/matching-list.effekt @@ -19,10 +19,10 @@ def ex3(lst: List[List[Int]]) = { x } -def foo(lst: List[Int]) { f: List[Int] => Unit } = f(lst) +def foo(lst: List[Int]) { f: List[Int] => Int } = f(lst) def ex4(lst: List[Int]) = foo(lst) { - case [a, b, c] => println(a + b + c) + case [a, b, c] => a + b + c case _ => panic("Ohno") }