Skip to content

Commit 74ff5ef

Browse files
committed
Allow case in front of generators (syntax and parsing)
1 parent 0e66a88 commit 74ff5ef

File tree

7 files changed

+52
-36
lines changed

7 files changed

+52
-36
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,25 +1358,25 @@ object desugar {
13581358
enums match {
13591359
case (gen: GenFrom) :: Nil =>
13601360
Apply(rhsSelect(gen, mapName), makeLambda(gen.pat, body))
1361-
case (gen: GenFrom) :: (rest @ (GenFrom(_, _) :: _)) =>
1361+
case (gen: GenFrom) :: (rest @ (GenFrom(_, _, _) :: _)) =>
13621362
val cont = makeFor(mapName, flatMapName, rest, body)
13631363
Apply(rhsSelect(gen, flatMapName), makeLambda(gen.pat, cont))
1364-
case (GenFrom(pat, rhs)) :: (rest @ GenAlias(_, _) :: _) =>
1364+
case (gen @ GenFrom(pat, rhs, _)) :: (rest @ GenAlias(_, _) :: _) =>
13651365
val (valeqs, rest1) = rest.span(_.isInstanceOf[GenAlias])
13661366
val pats = valeqs map { case GenAlias(pat, _) => pat }
13671367
val rhss = valeqs map { case GenAlias(_, rhs) => rhs }
13681368
val (defpat0, id0) = makeIdPat(pat)
13691369
val (defpats, ids) = (pats map makeIdPat).unzip
13701370
val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers(), _, _))
1371-
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, rhs) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
1371+
val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom(defpat0, rhs, gen.filtering) :: Nil, Block(pdefs, makeTuple(id0 :: ids)))
13721372
val allpats = pat :: pats
13731373
val vfrom1 = new IrrefutableGenFrom(makeTuple(allpats), rhs1)
13741374
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
13751375
case (gen: GenFrom) :: test :: rest =>
13761376
val filtered = Apply(rhsSelect(gen, nme.withFilter), makeLambda(gen.pat, test))
13771377
val genFrom =
13781378
if (isIrrefutableGenFrom(gen)) new IrrefutableGenFrom(gen.pat, filtered)
1379-
else GenFrom(gen.pat, filtered)
1379+
else GenFrom(gen.pat, filtered, filtering = false)
13801380
makeFor(mapName, flatMapName, genFrom :: rest, body)
13811381
case _ =>
13821382
EmptyTree //may happen for erroneous input
@@ -1573,5 +1573,5 @@ object desugar {
15731573
}
15741574

15751575
private class IrrefutableGenFrom(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile)
1576-
extends GenFrom(pat, expr)
1576+
extends GenFrom(pat, expr, false)
15771577
}

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
9999
case class DoWhile(body: Tree, cond: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
100100
case class ForYield(enums: List[Tree], expr: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
101101
case class ForDo(enums: List[Tree], body: Tree)(implicit @constructorOnly src: SourceFile) extends TermTree
102-
case class GenFrom(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
102+
case class GenFrom(pat: Tree, expr: Tree, filtering: Boolean)(implicit @constructorOnly src: SourceFile) extends Tree
103103
case class GenAlias(pat: Tree, expr: Tree)(implicit @constructorOnly src: SourceFile) extends Tree
104104
case class ContextBounds(bounds: TypeBoundsTree, cxBounds: List[Tree])(implicit @constructorOnly src: SourceFile) extends TypTree
105105
case class PatDef(mods: Modifiers, pats: List[Tree], tpt: Tree, rhs: Tree)(implicit @constructorOnly src: SourceFile) extends DefTree
@@ -525,9 +525,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
525525
case tree: ForDo if (enums eq tree.enums) && (body eq tree.body) => tree
526526
case _ => finalize(tree, untpd.ForDo(enums, body)(tree.source))
527527
}
528-
def GenFrom(tree: Tree)(pat: Tree, expr: Tree)(implicit ctx: Context): Tree = tree match {
529-
case tree: GenFrom if (pat eq tree.pat) && (expr eq tree.expr) => tree
530-
case _ => finalize(tree, untpd.GenFrom(pat, expr)(tree.source))
528+
def GenFrom(tree: Tree)(pat: Tree, expr: Tree, filtering: Boolean)(implicit ctx: Context): Tree = tree match {
529+
case tree: GenFrom if (pat eq tree.pat) && (expr eq tree.expr) && (filtering == tree.filtering) => tree
530+
case _ => finalize(tree, untpd.GenFrom(pat, expr, filtering)(tree.source))
531531
}
532532
def GenAlias(tree: Tree)(pat: Tree, expr: Tree)(implicit ctx: Context): Tree = tree match {
533533
case tree: GenAlias if (pat eq tree.pat) && (expr eq tree.expr) => tree
@@ -589,8 +589,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
589589
cpy.ForYield(tree)(transform(enums), transform(expr))
590590
case ForDo(enums, body) =>
591591
cpy.ForDo(tree)(transform(enums), transform(body))
592-
case GenFrom(pat, expr) =>
593-
cpy.GenFrom(tree)(transform(pat), transform(expr))
592+
case GenFrom(pat, expr, filtering) =>
593+
cpy.GenFrom(tree)(transform(pat), transform(expr), filtering)
594594
case GenAlias(pat, expr) =>
595595
cpy.GenAlias(tree)(transform(pat), transform(expr))
596596
case ContextBounds(bounds, cxBounds) =>
@@ -644,7 +644,7 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
644644
this(this(x, enums), expr)
645645
case ForDo(enums, body) =>
646646
this(this(x, enums), body)
647-
case GenFrom(pat, expr) =>
647+
case GenFrom(pat, expr, _) =>
648648
this(this(x, pat), expr)
649649
case GenAlias(pat, expr) =>
650650
this(this(x, pat), expr)

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,18 +1725,24 @@ object Parsers {
17251725
*/
17261726
def enumerator(): Tree =
17271727
if (in.token == IF) guard()
1728+
else if (in.token == CASE) generator()
17281729
else {
17291730
val pat = pattern1()
17301731
if (in.token == EQUALS) atSpan(startOffset(pat), in.skipToken()) { GenAlias(pat, expr()) }
1731-
else generatorRest(pat)
1732+
else generatorRest(pat, filtering = false)
17321733
}
17331734

1734-
/** Generator ::= Pattern `<-' Expr
1735+
/** Generator ::= [‘case’] Pattern `<-' Expr
17351736
*/
1736-
def generator(): Tree = generatorRest(pattern1())
1737+
def generator(): Tree = {
1738+
val filtering =
1739+
if (in.token == CASE) { in.skipCASE(); true }
1740+
else !ctx.settings.strict.value // don't filter under -strict
1741+
generatorRest(pattern1(), filtering)
1742+
}
17371743

1738-
def generatorRest(pat: Tree): GenFrom =
1739-
atSpan(startOffset(pat), accept(LARROW)) { GenFrom(pat, expr()) }
1744+
def generatorRest(pat: Tree, filtering: Boolean): GenFrom =
1745+
atSpan(startOffset(pat), accept(LARROW)) { GenFrom(pat, expr(), filtering) }
17401746

17411747
/** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}')
17421748
* {nl} [`yield'] Expr
@@ -1749,16 +1755,20 @@ object Parsers {
17491755
else if (in.token == LPAREN) {
17501756
val lparenOffset = in.skipToken()
17511757
openParens.change(LPAREN, 1)
1752-
val pats = patternsOpt()
1753-
val pat =
1754-
if (in.token == RPAREN || pats.length > 1) {
1755-
wrappedEnums = false
1756-
accept(RPAREN)
1757-
openParens.change(LPAREN, -1)
1758-
atSpan(lparenOffset) { makeTupleOrParens(pats) } // note: alternatives `|' need to be weeded out by typer.
1758+
val res =
1759+
if (in.token == CASE) enumerators()
1760+
else {
1761+
val pats = patternsOpt()
1762+
val pat =
1763+
if (in.token == RPAREN || pats.length > 1) {
1764+
wrappedEnums = false
1765+
accept(RPAREN)
1766+
openParens.change(LPAREN, -1)
1767+
atSpan(lparenOffset) { makeTupleOrParens(pats) } // note: alternatives `|' need to be weeded out by typer.
1768+
}
1769+
else pats.head
1770+
generatorRest(pat, filtering = false) :: enumeratorsRest()
17591771
}
1760-
else pats.head
1761-
val res = generatorRest(pat) :: enumeratorsRest()
17621772
if (wrappedEnums) {
17631773
accept(RPAREN)
17641774
openParens.change(LPAREN, -1)
@@ -2640,11 +2650,7 @@ object Parsers {
26402650
*/
26412651
def enumCase(start: Offset, mods: Modifiers): DefTree = {
26422652
val mods1 = addMod(mods, atSpan(in.offset)(Mod.Enum())) | Case
2643-
accept(CASE)
2644-
2645-
in.adjustSepRegions(ARROW)
2646-
// Scanner thinks it is in a pattern match after seeing the `case`.
2647-
// We need to get it out of that mode by telling it we are past the `=>`
2653+
in.skipCASE()
26482654

26492655
atSpan(start, nameStart) {
26502656
val id = termIdent()

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,16 @@ object Scanners {
351351
case _ =>
352352
}
353353

354+
/** Advance beyond a case token without marking the CASE in sepRegions.
355+
* This method should be called to skip beyond CASE tokens that are
356+
* not part of matches, i.e. no ARROW is expected after them.
357+
*/
358+
def skipCASE() = {
359+
assert(token == CASE)
360+
nextToken()
361+
sepRegions = sepRegions.tail
362+
}
363+
354364
/** Produce next token, filling TokenData fields of Scanner.
355365
*/
356366
def nextToken(): Unit = {

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
570570
forText(enums, expr, keywordStr(" yield "))
571571
case ForDo(enums, expr) =>
572572
forText(enums, expr, keywordStr(" do "))
573-
case GenFrom(pat, expr) =>
574-
toText(pat) ~ " <- " ~ toText(expr)
573+
case GenFrom(pat, expr, filtering) =>
574+
(Str("case ") provided filtering) ~ toText(pat) ~ " <- " ~ toText(expr)
575575
case GenAlias(pat, expr) =>
576576
toText(pat) ~ " = " ~ toText(expr)
577577
case ContextBounds(bounds, cxBounds) =>

compiler/test/dotty/tools/dotc/parsing/parsePackage.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ object parsePackage extends ParserTest {
4949
ForYield(enums map transform, transform(expr))
5050
case ForDo(enums, expr) =>
5151
ForDo(enums map transform, transform(expr))
52-
case GenFrom(pat, expr) =>
53-
GenFrom(transform(pat), transform(expr))
52+
case GenFrom(pat, expr, filtering) =>
53+
GenFrom(transform(pat), transform(expr), filtering)
5454
case GenAlias(pat, expr) =>
5555
GenAlias(transform(pat), transform(expr))
5656
case PatDef(mods, pats, tpt, expr) =>

docs/docs/internals/syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ Enumerators ::= Generator {semi Enumerator | Guard}
245245
Enumerator ::= Generator
246246
| Guard
247247
| Pattern1 ‘=’ Expr GenAlias(pat, expr)
248-
Generator ::= Pattern1 ‘<-’ Expr GenFrom(pat, expr)
248+
Generator ::= [‘case’] Pattern1 ‘<-’ Expr GenFrom(pat, expr)
249249
Guard ::= ‘if’ PostfixExpr
250250
251251
CaseClauses ::= CaseClause { CaseClause } Match(EmptyTree, cases)

0 commit comments

Comments
 (0)