Skip to content

Commit 59bddd4

Browse files
committed
Allow single case clauses as expressions
1 parent 271f18f commit 59bddd4

File tree

3 files changed

+34
-5
lines changed

3 files changed

+34
-5
lines changed

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,6 +2383,7 @@ object Parsers {
23832383

23842384
/** Expr ::= [`implicit'] FunParams (‘=>’ | ‘?=>’) Expr
23852385
* | TypTypeParamClause ‘=>’ Expr
2386+
* | ExprCaseClause
23862387
* | Expr1
23872388
* FunParams ::= Bindings
23882389
* | id
@@ -2434,6 +2435,8 @@ object Parsers {
24342435
val arrowOffset = accept(ARROW)
24352436
val body = expr(location)
24362437
makePolyFunction(tparams, body, "literal", errorTermTree(arrowOffset), start, arrowOffset)
2438+
case CASE =>
2439+
singleCaseMatch()
24372440
case _ =>
24382441
val saved = placeholderParams
24392442
placeholderParams = Nil
@@ -2497,9 +2500,8 @@ object Parsers {
24972500
if in.token == CATCH then
24982501
val span = in.offset
24992502
in.nextToken()
2500-
(if in.token == CASE then Match(EmptyTree, caseClause(exprOnly = true) :: Nil)
2501-
else subExpr(),
2502-
span)
2503+
(if in.token == CASE then singleCaseMatch() else subExpr(),
2504+
span)
25032505
else (EmptyTree, -1)
25042506

25052507
handler match {
@@ -3193,9 +3195,9 @@ object Parsers {
31933195
case ARROW => atSpan(in.skipToken()):
31943196
if exprOnly then
31953197
if in.indentSyntax && in.isAfterLineEnd && in.token != INDENT then
3196-
warning(em"""Misleading indentation: this expression forms part of the preceding catch case.
3198+
warning(em"""Misleading indentation: this expression forms part of the preceding case.
31973199
|If this is intended, it should be indented for clarity.
3198-
|Otherwise, if the handler is intended to be empty, use a multi-line catch with
3200+
|Otherwise, if the handler is intended to be empty, use a multi-line match or catch with
31993201
|an indented case.""")
32003202
expr()
32013203
else block()
@@ -3212,6 +3214,9 @@ object Parsers {
32123214
CaseDef(pat, grd1, body)
32133215
}
32143216

3217+
def singleCaseMatch() =
3218+
Match(EmptyTree, caseClause(exprOnly = true) :: Nil)
3219+
32153220
/** TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi]
32163221
*/
32173222
def typeCaseClause(): CaseDef = atSpan(in.offset) {

docs/_docs/internals/syntax.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ CapFilter ::= ‘.’ ‘as’ ‘[’ QualId ’]’
243243
```ebnf
244244
Expr ::= FunParams (‘=>’ | ‘?=>’) Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
245245
| TypTypeParamClause ‘=>’ Expr PolyFunction(ts, expr)
246+
| ExprCaseClause
246247
| Expr1
247248
BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
248249
| TypTypeParamClause ‘=>’ Block
@@ -295,6 +296,8 @@ SimpleExpr ::= SimpleRef
295296
| XmlExpr -- to be dropped
296297
ColonArgument ::= colon [LambdaStart]
297298
indent (CaseClauses | Block) outdent
299+
| colon LambdaStart expr ENDlambda -- ENDlambda is inserted for each production at next EOL
300+
-- does not apply if enclosed in parens
298301
LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
299302
| TypTypeParamClause ‘=>’
300303
Quoted ::= ‘'’ ‘{’ Block ‘}’

tests/run/single-case-expr.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
case class Foo(x: Int, y: Int)
2+
@main def Test =
3+
val f: List[Int] => Int = case y :: ys => y
4+
val xs = List(1, 2, 3)
5+
assert(f(xs) == 1)
6+
7+
val g: Foo => Int = identity(case Foo(a, b) => a)
8+
val foo = Foo(1, 2)
9+
assert(g(foo) == 1)
10+
11+
val a1 = Seq((1, 2), (3, 4)).collect(case (a, b) if b > 2 => a)
12+
assert(a1 == Seq(3))
13+
14+
var a2 = Seq((1, 2), (3, 4)).collect(
15+
case (a, b) =>
16+
println(b)
17+
a
18+
)
19+
assert(a2 == Seq(1, 3))
20+
21+
val partial: PartialFunction[(Int, Int), Int] = case (a, b) if b > 2 => a

0 commit comments

Comments
 (0)