Skip to content

Commit 3ae53ff

Browse files
committed
Allow single case clauses as expressions
1 parent 2b554d4 commit 3ae53ff

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
@@ -2378,6 +2378,7 @@ object Parsers {
23782378

23792379
/** Expr ::= [`implicit'] FunParams (‘=>’ | ‘?=>’) Expr
23802380
* | TypTypeParamClause ‘=>’ Expr
2381+
* | ExprCaseClause
23812382
* | Expr1
23822383
* FunParams ::= Bindings
23832384
* | id
@@ -2429,6 +2430,8 @@ object Parsers {
24292430
val arrowOffset = accept(ARROW)
24302431
val body = expr(location)
24312432
makePolyFunction(tparams, body, "literal", errorTermTree(arrowOffset), start, arrowOffset)
2433+
case CASE =>
2434+
singleCaseMatch()
24322435
case _ =>
24332436
val saved = placeholderParams
24342437
placeholderParams = Nil
@@ -2492,9 +2495,8 @@ object Parsers {
24922495
if in.token == CATCH then
24932496
val span = in.offset
24942497
in.nextToken()
2495-
(if in.token == CASE then Match(EmptyTree, caseClause(exprOnly = true) :: Nil)
2496-
else subExpr(),
2497-
span)
2498+
(if in.token == CASE then singleCaseMatch() else subExpr(),
2499+
span)
24982500
else (EmptyTree, -1)
24992501

25002502
handler match {
@@ -3188,9 +3190,9 @@ object Parsers {
31883190
case ARROW => atSpan(in.skipToken()):
31893191
if exprOnly then
31903192
if in.indentSyntax && in.isAfterLineEnd && in.token != INDENT then
3191-
warning(em"""Misleading indentation: this expression forms part of the preceding catch case.
3193+
warning(em"""Misleading indentation: this expression forms part of the preceding case.
31923194
|If this is intended, it should be indented for clarity.
3193-
|Otherwise, if the handler is intended to be empty, use a multi-line catch with
3195+
|Otherwise, if the handler is intended to be empty, use a multi-line match or catch with
31943196
|an indented case.""")
31953197
expr()
31963198
else block()
@@ -3206,6 +3208,9 @@ object Parsers {
32063208
CaseDef(pat, grd1, body)
32073209
}
32083210

3211+
def singleCaseMatch() =
3212+
Match(EmptyTree, caseClause(exprOnly = true) :: Nil)
3213+
32093214
/** TypeCaseClause ::= ‘case’ (InfixType | ‘_’) ‘=>’ Type [semi]
32103215
*/
32113216
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)