Skip to content

Allow braces just on the outside of polymorphic lambdas #12280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 37 additions & 36 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1838,13 +1838,15 @@ object Parsers {
t

/** Expr ::= [`implicit'] FunParams (‘=>’ | ‘?=>’) Expr
* | HkTypeParamClause ‘=>’ Expr
* | Expr1
* FunParams ::= Bindings
* | id
* | `_'
* ExprInParens ::= PostfixExpr `:' Type
* | Expr
* BlockResult ::= [‘implicit’] FunParams (‘=>’ | ‘?=>’) Block
* | HkTypeParamClause ‘=>’ Block
* | Expr1
* Expr1 ::= [‘inline’] `if' `(' Expr `)' {nl} Expr [[semi] else Expr]
* | [‘inline’] `if' Expr `then' Expr [[semi] else Expr]
Expand All @@ -1855,7 +1857,6 @@ object Parsers {
* | `throw' Expr
* | `return' [Expr]
* | ForExpr
* | HkTypeParamClause ‘=>’ Expr
* | [SimpleExpr `.'] id `=' Expr
* | SimpleExpr1 ArgumentExprs `=' Expr
* | PostfixExpr [Ascription]
Expand All @@ -1876,28 +1877,41 @@ object Parsers {
def expr(location: Location): Tree = {
val start = in.offset
def isSpecialClosureStart = in.lookahead.isIdent(nme.erased) && in.erasedEnabled
if in.token == IMPLICIT then
closure(start, location, modifiers(BitSet(IMPLICIT)))
else if in.token == LPAREN && isSpecialClosureStart then
closure(start, location, Modifiers())
else {
val saved = placeholderParams
placeholderParams = Nil

def wrapPlaceholders(t: Tree) = try
if (placeholderParams.isEmpty) t
else new WildcardFunction(placeholderParams.reverse, t)
finally placeholderParams = saved

val t = expr1(location)
if in.isArrow then
placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder
wrapPlaceholders(closureRest(start, location, convertToParams(t)))
else if isWildcard(t) then
placeholderParams = placeholderParams ::: saved
t
else wrapPlaceholders(t)
}
in.token match
case IMPLICIT =>
closure(start, location, modifiers(BitSet(IMPLICIT)))
case LPAREN if isSpecialClosureStart =>
closure(start, location, Modifiers())
case LBRACKET =>
val start = in.offset
val tparams = typeParamClause(ParamOwner.TypeParam)
val arrowOffset = accept(ARROW)
val body = expr(location)
atSpan(start, arrowOffset) {
if (isFunction(body))
PolyFunction(tparams, body)
else {
syntaxError("Implementation restriction: polymorphic function literals must have a value parameter", arrowOffset)
errorTermTree
}
}
case _ =>
val saved = placeholderParams
placeholderParams = Nil

def wrapPlaceholders(t: Tree) = try
if (placeholderParams.isEmpty) t
else new WildcardFunction(placeholderParams.reverse, t)
finally placeholderParams = saved

val t = expr1(location)
if in.isArrow then
placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder
wrapPlaceholders(closureRest(start, location, convertToParams(t)))
else if isWildcard(t) then
placeholderParams = placeholderParams ::: saved
t
else wrapPlaceholders(t)
}

def expr1(location: Location = Location.ElseWhere): Tree = in.token match
Expand Down Expand Up @@ -1981,19 +1995,6 @@ object Parsers {
}
case FOR =>
forExpr()
case LBRACKET =>
val start = in.offset
val tparams = typeParamClause(ParamOwner.TypeParam)
val arrowOffset = accept(ARROW)
val body = expr()
atSpan(start, arrowOffset) {
if (isFunction(body))
PolyFunction(tparams, body)
else {
syntaxError("Implementation restriction: polymorphic function literals must have a value parameter", arrowOffset)
errorTermTree
}
}
case _ =>
if isIdent(nme.inline)
&& !in.inModifierPosition()
Expand Down
3 changes: 2 additions & 1 deletion docs/docs/internals/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,10 @@ Types ::= Type {‘,’ Type}
### Expressions
```ebnf
Expr ::= FunParams (‘=>’ | ‘?=>’) Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
| HkTypeParamClause ‘=>’ Expr PolyFunction(ts, expr)
| Expr1
BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
| HkTypeParamClause ‘=>’ Block
| Expr1
FunParams ::= Bindings
| id
Expand All @@ -220,7 +222,6 @@ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[
| ‘throw’ Expr Throw(expr)
| ‘return’ [Expr] Return(expr?)
| ForExpr
| HkTypeParamClause ‘=>’ Expr PolyFunction(ts, expr)
| [SimpleExpr ‘.’] id ‘=’ Expr Assign(expr, expr)
| SimpleExpr1 ArgumentExprs ‘=’ Expr Assign(expr, expr)
| PostfixExpr [Ascription]
Expand Down
3 changes: 2 additions & 1 deletion docs/docs/reference/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,10 @@ Types ::= Type {‘,’ Type}
### Expressions
```ebnf
Expr ::= FunParams (‘=>’ | ‘?=>’) Expr
| HkTypeParamClause ‘=>’ Expr
| Expr1
BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
| HkTypeParamClause ‘=>’ Block
| Expr1
FunParams ::= Bindings
| id
Expand All @@ -217,7 +219,6 @@ Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[
| ‘throw’ Expr
| ‘return’ [Expr]
| ForExpr
| HkTypeParamClause ‘=>’ Expr
| [SimpleExpr ‘.’] id ‘=’ Expr
| SimpleExpr1 ArgumentExprs ‘=’ Expr
| PostfixExpr [Ascription]
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/tuple-ops.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ val r3: ((2, 1), (8, 2)) = c.zip(a) // error
// Map
case class Foo[X](x: X)

val r6: (Int, Int, String) = a.map[[t] =>> Int]([t] => x: t => x match { // error
val r6: (Int, Int, String) = a.map[[t] =>> Int]([t] => (x: t) => x match { // error
case x: Int => x * x
case _ => ???
})

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

// More Zip
val t1: Int *: Long *: Tuple = (1, 2l, 100, 200)
Expand Down
18 changes: 18 additions & 0 deletions tests/pos/i12277.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
def foo(f: => () => Unit): Unit = ???
def boo(f: [A] => () => Unit): Unit = ???

object test:
foo { () => // okay
println(1)
println(2)
}

boo { [A] => () => // error
println(1)
println(2)
}

boo { [A] => () => { // okay
println(1)
println(2)
}}