Skip to content

Commit 2895cb3

Browse files
oderskymichelou
authored andcommitted
Allow braces just on the outside of polymorphic lambdas
Also refactor grammar so that polymorphic lambdas and regular lambdas have the same level of precedence. Fixes scala#12277
1 parent dbe6dd8 commit 2895cb3

File tree

5 files changed

+61
-40
lines changed

5 files changed

+61
-40
lines changed

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

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,13 +1838,15 @@ object Parsers {
18381838
t
18391839

18401840
/** Expr ::= [`implicit'] FunParams (‘=>’ | ‘?=>’) Expr
1841+
* | HkTypeParamClause ‘=>’ Expr
18411842
* | Expr1
18421843
* FunParams ::= Bindings
18431844
* | id
18441845
* | `_'
18451846
* ExprInParens ::= PostfixExpr `:' Type
18461847
* | Expr
18471848
* BlockResult ::= [‘implicit’] FunParams (‘=>’ | ‘?=>’) Block
1849+
* | HkTypeParamClause ‘=>’ Block
18481850
* | Expr1
18491851
* Expr1 ::= [‘inline’] `if' `(' Expr `)' {nl} Expr [[semi] else Expr]
18501852
* | [‘inline’] `if' Expr `then' Expr [[semi] else Expr]
@@ -1855,7 +1857,6 @@ object Parsers {
18551857
* | `throw' Expr
18561858
* | `return' [Expr]
18571859
* | ForExpr
1858-
* | HkTypeParamClause ‘=>’ Expr
18591860
* | [SimpleExpr `.'] id `=' Expr
18601861
* | SimpleExpr1 ArgumentExprs `=' Expr
18611862
* | PostfixExpr [Ascription]
@@ -1876,28 +1877,41 @@ object Parsers {
18761877
def expr(location: Location): Tree = {
18771878
val start = in.offset
18781879
def isSpecialClosureStart = in.lookahead.isIdent(nme.erased) && in.erasedEnabled
1879-
if in.token == IMPLICIT then
1880-
closure(start, location, modifiers(BitSet(IMPLICIT)))
1881-
else if in.token == LPAREN && isSpecialClosureStart then
1882-
closure(start, location, Modifiers())
1883-
else {
1884-
val saved = placeholderParams
1885-
placeholderParams = Nil
1886-
1887-
def wrapPlaceholders(t: Tree) = try
1888-
if (placeholderParams.isEmpty) t
1889-
else new WildcardFunction(placeholderParams.reverse, t)
1890-
finally placeholderParams = saved
1891-
1892-
val t = expr1(location)
1893-
if in.isArrow then
1894-
placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder
1895-
wrapPlaceholders(closureRest(start, location, convertToParams(t)))
1896-
else if isWildcard(t) then
1897-
placeholderParams = placeholderParams ::: saved
1898-
t
1899-
else wrapPlaceholders(t)
1900-
}
1880+
in.token match
1881+
case IMPLICIT =>
1882+
closure(start, location, modifiers(BitSet(IMPLICIT)))
1883+
case LPAREN if isSpecialClosureStart =>
1884+
closure(start, location, Modifiers())
1885+
case LBRACKET =>
1886+
val start = in.offset
1887+
val tparams = typeParamClause(ParamOwner.TypeParam)
1888+
val arrowOffset = accept(ARROW)
1889+
val body = expr(location)
1890+
atSpan(start, arrowOffset) {
1891+
if (isFunction(body))
1892+
PolyFunction(tparams, body)
1893+
else {
1894+
syntaxError("Implementation restriction: polymorphic function literals must have a value parameter", arrowOffset)
1895+
errorTermTree
1896+
}
1897+
}
1898+
case _ =>
1899+
val saved = placeholderParams
1900+
placeholderParams = Nil
1901+
1902+
def wrapPlaceholders(t: Tree) = try
1903+
if (placeholderParams.isEmpty) t
1904+
else new WildcardFunction(placeholderParams.reverse, t)
1905+
finally placeholderParams = saved
1906+
1907+
val t = expr1(location)
1908+
if in.isArrow then
1909+
placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder
1910+
wrapPlaceholders(closureRest(start, location, convertToParams(t)))
1911+
else if isWildcard(t) then
1912+
placeholderParams = placeholderParams ::: saved
1913+
t
1914+
else wrapPlaceholders(t)
19011915
}
19021916

19031917
def expr1(location: Location = Location.ElseWhere): Tree = in.token match
@@ -1981,19 +1995,6 @@ object Parsers {
19811995
}
19821996
case FOR =>
19831997
forExpr()
1984-
case LBRACKET =>
1985-
val start = in.offset
1986-
val tparams = typeParamClause(ParamOwner.TypeParam)
1987-
val arrowOffset = accept(ARROW)
1988-
val body = expr()
1989-
atSpan(start, arrowOffset) {
1990-
if (isFunction(body))
1991-
PolyFunction(tparams, body)
1992-
else {
1993-
syntaxError("Implementation restriction: polymorphic function literals must have a value parameter", arrowOffset)
1994-
errorTermTree
1995-
}
1996-
}
19971998
case _ =>
19981999
if isIdent(nme.inline)
19992000
&& !in.inModifierPosition()

docs/docs/internals/syntax.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,10 @@ Types ::= Type {‘,’ Type}
205205
### Expressions
206206
```ebnf
207207
Expr ::= FunParams (‘=>’ | ‘?=>’) Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
208+
| HkTypeParamClause ‘=>’ Expr PolyFunction(ts, expr)
208209
| Expr1
209210
BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
211+
| HkTypeParamClause ‘=>’ Block
210212
| Expr1
211213
FunParams ::= Bindings
212214
| id
@@ -220,7 +222,6 @@ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[
220222
| ‘throw’ Expr Throw(expr)
221223
| ‘return’ [Expr] Return(expr?)
222224
| ForExpr
223-
| HkTypeParamClause ‘=>’ Expr PolyFunction(ts, expr)
224225
| [SimpleExpr ‘.’] id ‘=’ Expr Assign(expr, expr)
225226
| SimpleExpr1 ArgumentExprs ‘=’ Expr Assign(expr, expr)
226227
| PostfixExpr [Ascription]

docs/docs/reference/syntax.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,10 @@ Types ::= Type {‘,’ Type}
202202
### Expressions
203203
```ebnf
204204
Expr ::= FunParams (‘=>’ | ‘?=>’) Expr
205+
| HkTypeParamClause ‘=>’ Expr
205206
| Expr1
206207
BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
208+
| HkTypeParamClause ‘=>’ Block
207209
| Expr1
208210
FunParams ::= Bindings
209211
| id
@@ -217,7 +219,6 @@ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[
217219
| ‘throw’ Expr
218220
| ‘return’ [Expr]
219221
| ForExpr
220-
| HkTypeParamClause ‘=>’ Expr
221222
| [SimpleExpr ‘.’] id ‘=’ Expr
222223
| SimpleExpr1 ArgumentExprs ‘=’ Expr
223224
| PostfixExpr [Ascription]

tests/neg/tuple-ops.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ val r3: ((2, 1), (8, 2)) = c.zip(a) // error
1212
// Map
1313
case class Foo[X](x: X)
1414

15-
val r6: (Int, Int, String) = a.map[[t] =>> Int]([t] => x: t => x match { // error
15+
val r6: (Int, Int, String) = a.map[[t] =>> Int]([t] => (x: t) => x match { // error
1616
case x: Int => x * x
1717
case _ => ???
1818
})
1919

2020
val r7: ((1, Foo[1]), (2), (3, Foo[3])) =
21-
a.map[[t] =>> (t, Foo[t])]( [t] => x: t => (x, Foo(x)) ) // error
21+
a.map[[t] =>> (t, Foo[t])]( [t] => (x: t) => (x, Foo(x)) ) // error
2222

2323
// More Zip
2424
val t1: Int *: Long *: Tuple = (1, 2l, 100, 200)

tests/pos/i12277.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
def foo(f: => () => Unit): Unit = ???
2+
def boo(f: [A] => () => Unit): Unit = ???
3+
4+
object test:
5+
foo { () => // okay
6+
println(1)
7+
println(2)
8+
}
9+
10+
boo { [A] => () => // error
11+
println(1)
12+
println(2)
13+
}
14+
15+
boo { [A] => () => { // okay
16+
println(1)
17+
println(2)
18+
}}

0 commit comments

Comments
 (0)