Skip to content

Commit dbfde1c

Browse files
committed
Add closure arguments, first version
1 parent 2093b93 commit dbfde1c

File tree

7 files changed

+114
-51
lines changed

7 files changed

+114
-51
lines changed

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

Lines changed: 85 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ object Parsers {
4343
case InParens extends Location(true, false, false)
4444
case InArgs extends Location(true, false, true)
4545
case InPattern extends Location(false, true, false)
46+
case InGuard extends Location(false, false, false)
4647
case InPatternArgs extends Location(false, true, true) // InParens not true, since it might be an alternative
4748
case InBlock extends Location(false, false, false)
4849
case ElseWhere extends Location(false, false, false)
@@ -403,22 +404,23 @@ object Parsers {
403404

404405
/** Convert tree to formal parameter list
405406
*/
406-
def convertToParams(tree: Tree, mods: Modifiers): List[ValDef] = tree match {
407-
case Parens(t) =>
408-
convertToParam(t, mods) :: Nil
409-
case Tuple(ts) =>
410-
ts.map(convertToParam(_, mods))
411-
case t: Typed =>
412-
report.errorOrMigrationWarning(
413-
em"parentheses are required around the parameter of a lambda${rewriteNotice()}",
414-
in.sourcePos())
415-
if migrateTo3 then
416-
patch(source, t.span.startPos, "(")
417-
patch(source, t.span.endPos, ")")
418-
convertToParam(t, mods) :: Nil
419-
case t =>
420-
convertToParam(t, mods) :: Nil
421-
}
407+
def convertToParams(tree: Tree): List[ValDef] =
408+
val mods = if in.token == CTXARROW then Modifiers(Given) else EmptyModifiers
409+
tree match
410+
case Parens(t) =>
411+
convertToParam(t, mods) :: Nil
412+
case Tuple(ts) =>
413+
ts.map(convertToParam(_, mods))
414+
case t: Typed =>
415+
report.errorOrMigrationWarning(
416+
em"parentheses are required around the parameter of a lambda${rewriteNotice()}",
417+
in.sourcePos())
418+
if migrateTo3 then
419+
patch(source, t.span.startPos, "(")
420+
patch(source, t.span.endPos, ")")
421+
convertToParam(t, mods) :: Nil
422+
case t =>
423+
convertToParam(t, mods) :: Nil
422424

423425
/** Convert tree to formal parameter
424426
*/
@@ -920,7 +922,8 @@ object Parsers {
920922
* @param maybePostfix postfix operators are allowed.
921923
*/
922924
def infixOps(
923-
first: Tree, canStartOperand: Token => Boolean, operand: () => Tree,
925+
first: Tree, canStartOperand: Token => Boolean, operand: Location => Tree,
926+
location: Location,
924927
isType: Boolean,
925928
isOperator: => Boolean,
926929
maybePostfix: Boolean = false): Tree = {
@@ -941,7 +944,7 @@ object Parsers {
941944
PostfixOp(od, topInfo.operator)
942945
}
943946
}
944-
else recur(operand())
947+
else recur(operand(location))
945948
}
946949
else
947950
val t = reduceStack(base, top, minPrec, leftAssoc = true, in.name, isType)
@@ -1488,12 +1491,15 @@ object Parsers {
14881491
def infixType(): Tree = infixTypeRest(refinedType())
14891492

14901493
def infixTypeRest(t: Tree): Tree =
1491-
infixOps(t, canStartTypeTokens, refinedType, isType = true,
1494+
infixOps(t, canStartTypeTokens, refinedTypeFn, Location.ElseWhere,
1495+
isType = true,
14921496
isOperator = !followingIsVararg())
14931497

14941498
/** RefinedType ::= WithType {[nl] Refinement}
14951499
*/
1496-
val refinedType: () => Tree = () => refinedTypeRest(withType())
1500+
val refinedTypeFn: Location => Tree = _ => refinedType()
1501+
1502+
def refinedType() = refinedTypeRest(withType())
14971503

14981504
def refinedTypeRest(t: Tree): Tree = {
14991505
argumentStart()
@@ -1811,7 +1817,11 @@ object Parsers {
18111817
if in.token != altToken then
18121818
if toBeContinued(altToken) then
18131819
t = inSepRegion(InCond) {
1814-
expr1Rest(postfixExprRest(simpleExprRest(t)), Location.ElseWhere)
1820+
expr1Rest(
1821+
postfixExprRest(
1822+
simpleExprRest(t, Location.ElseWhere),
1823+
Location.ElseWhere),
1824+
Location.ElseWhere)
18151825
}
18161826
else
18171827
if rewriteToNewSyntax(t.span) then
@@ -1882,8 +1892,7 @@ object Parsers {
18821892
val t = expr1(location)
18831893
if in.isArrow then
18841894
placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder
1885-
val paramMods = if in.token == CTXARROW then Modifiers(Given) else EmptyModifiers
1886-
wrapPlaceholders(closureRest(start, location, convertToParams(t, paramMods)))
1895+
wrapPlaceholders(closureRest(start, location, convertToParams(t)))
18871896
else if isWildcard(t) then
18881897
placeholderParams = placeholderParams ::: saved
18891898
t
@@ -2155,30 +2164,30 @@ object Parsers {
21552164
* | InfixExpr MatchClause
21562165
*/
21572166
def postfixExpr(location: Location = Location.ElseWhere): Tree =
2158-
val t = postfixExprRest(prefixExpr(), location)
2167+
val t = postfixExprRest(prefixExpr(location), location)
21592168
if location.inArgs && followingIsVararg() then
21602169
Typed(t, atSpan(in.skipToken()) { Ident(tpnme.WILDCARD_STAR) })
21612170
else
21622171
t
21632172

2164-
def postfixExprRest(t: Tree, location: Location = Location.ElseWhere): Tree =
2165-
infixOps(t, in.canStartExprTokens, prefixExpr,
2173+
def postfixExprRest(t: Tree, location: Location): Tree =
2174+
infixOps(t, in.canStartExprTokens, prefixExpr, location,
21662175
isType = false,
21672176
isOperator = !(location.inArgs && followingIsVararg()),
21682177
maybePostfix = true)
21692178

21702179
/** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr
21712180
*/
2172-
val prefixExpr: () => Tree = () =>
2181+
val prefixExpr: Location => Tree = location =>
21732182
if (isIdent && nme.raw.isUnary(in.name)) {
21742183
val start = in.offset
21752184
val op = termIdent()
21762185
if (op.name == nme.raw.MINUS && isNumericLit)
2177-
simpleExprRest(literal(start), canApply = true)
2186+
simpleExprRest(literal(start), location, canApply = true)
21782187
else
2179-
atSpan(start) { PrefixOp(op, simpleExpr()) }
2188+
atSpan(start) { PrefixOp(op, simpleExpr(location)) }
21802189
}
2181-
else simpleExpr()
2190+
else simpleExpr(location)
21822191

21832192
/** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody]
21842193
* | ‘new’ TemplateBody
@@ -2195,11 +2204,12 @@ object Parsers {
21952204
* | SimpleExpr `.` MatchClause
21962205
* | SimpleExpr (TypeArgs | NamedTypeArgs)
21972206
* | SimpleExpr1 ArgumentExprs
2198-
* | SimpleExpr1 `:` nl ArgumentExprs
2207+
* | SimpleExpr1 :<<< BlockExpr >>> -- under language.experimental.fewerBraces
2208+
* | SimpleExpr1 FunParams (‘=>’ | ‘?=>’) indent Block outdent -- under language.experimental.fewerBraces
21992209
* Quoted ::= ‘'’ ‘{’ Block ‘}’
22002210
* | ‘'’ ‘[’ Type ‘]’
22012211
*/
2202-
def simpleExpr(): Tree = {
2212+
def simpleExpr(location: Location): Tree = {
22032213
var canApply = true
22042214
val t = in.token match {
22052215
case XMLSTART =>
@@ -2235,37 +2245,65 @@ object Parsers {
22352245
newExpr()
22362246
case MACRO =>
22372247
val start = in.skipToken()
2238-
MacroTree(simpleExpr())
2248+
MacroTree(simpleExpr(Location.ElseWhere))
22392249
case _ =>
22402250
if (isLiteral) literal()
22412251
else {
22422252
syntaxErrorOrIncomplete(IllegalStartSimpleExpr(tokenString(in.token)), expectedOffset)
22432253
errorTermTree
22442254
}
22452255
}
2246-
simpleExprRest(t, canApply)
2256+
simpleExprRest(t, location, canApply)
22472257
}
22482258

2249-
def simpleExprRest(t: Tree, canApply: Boolean = true): Tree = {
2259+
def simpleExprRest(t: Tree, location: Location, canApply: Boolean = true): Tree = {
22502260
if (canApply) argumentStart()
22512261
in.token match {
22522262
case DOT =>
22532263
in.nextToken()
2254-
simpleExprRest(selectorOrMatch(t), canApply = true)
2264+
simpleExprRest(selectorOrMatch(t), location, canApply = true)
22552265
case LBRACKET =>
22562266
val tapp = atSpan(startOffset(t), in.offset) { TypeApply(t, typeArgs(namedOK = true, wildOK = false)) }
2257-
simpleExprRest(tapp, canApply = true)
2267+
simpleExprRest(tapp, location, canApply = true)
22582268
case LPAREN | LBRACE | INDENT if canApply =>
2259-
val app = atSpan(startOffset(t), in.offset) { mkApply(t, argumentExprs()) }
2260-
simpleExprRest(app, canApply = true)
2269+
val inParents = in.token == LPAREN
2270+
val app = atSpan(startOffset(t), in.offset) {
2271+
val argExprs @ (args, isUsing) = argumentExprs()
2272+
if inParents && !isUsing && in.isArrow && location != Location.InGuard then
2273+
val params = convertToParams(Tuple(args))
2274+
if params.forall(_.name != nme.ERROR) then
2275+
applyToClosure(t, in.offset, params)
2276+
else
2277+
mkApply(t, argExprs)
2278+
else
2279+
mkApply(t, argExprs)
2280+
}
2281+
simpleExprRest(app, location, canApply = true)
22612282
case USCORE =>
2262-
if in.lookahead.isArrow then ???
2263-
else atSpan(startOffset(t), in.skipToken()) { PostfixOp(t, Ident(nme.WILDCARD)) }
2283+
if in.lookahead.isArrow && location != Location.InGuard then
2284+
val app = applyToClosure(t, in.offset, convertToParams(wildcardIdent()))
2285+
simpleExprRest(app, location, canApply = true)
2286+
else
2287+
atSpan(startOffset(t), in.skipToken()) { PostfixOp(t, Ident(nme.WILDCARD)) }
2288+
case IDENTIFIER if !in.isOperator && in.lookahead.isArrow && location != Location.InGuard =>
2289+
val app = applyToClosure(t, in.offset, convertToParams(termIdent()))
2290+
simpleExprRest(app, location, canApply = true)
22642291
case _ =>
22652292
t
22662293
}
22672294
}
22682295

2296+
def applyToClosure(t: Tree, start: Offset, params: List[ValDef]): Tree =
2297+
atSpan(startOffset(t), in.offset) {
2298+
val arg = atSpan(start, in.skipToken()) {
2299+
if in.token != INDENT then
2300+
syntaxErrorOrIncomplete(i"indented expression expected, ${in} found")
2301+
val body = inDefScopeBraces(block(simplify = true))
2302+
Function(params, body)
2303+
}
2304+
Apply(t, arg)
2305+
}
2306+
22692307
/** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody]
22702308
* | ‘new’ TemplateBody
22712309
*/
@@ -2382,7 +2420,7 @@ object Parsers {
23822420
/** Guard ::= if PostfixExpr
23832421
*/
23842422
def guard(): Tree =
2385-
if (in.token == IF) { in.nextToken(); postfixExpr() }
2423+
if (in.token == IF) { in.nextToken(); postfixExpr(Location.InGuard) }
23862424
else EmptyTree
23872425

23882426
/** Enumerators ::= Generator {semi Enumerator | Guard}
@@ -2607,7 +2645,7 @@ object Parsers {
26072645
/** InfixPattern ::= SimplePattern {id [nl] SimplePattern}
26082646
*/
26092647
def infixPattern(): Tree =
2610-
infixOps(simplePattern(), in.canStartExprTokens, simplePattern,
2648+
infixOps(simplePattern(), in.canStartExprTokens, simplePatternFn, Location.InPattern,
26112649
isType = false,
26122650
isOperator = in.name != nme.raw.BAR && !followingIsVararg())
26132651

@@ -2622,7 +2660,7 @@ object Parsers {
26222660
* PatVar ::= id
26232661
* | `_'
26242662
*/
2625-
val simplePattern: () => Tree = () => in.token match {
2663+
def simplePattern(): Tree = in.token match {
26262664
case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER =>
26272665
simpleRef() match
26282666
case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(startOffset(id))
@@ -2632,7 +2670,7 @@ object Parsers {
26322670
case LPAREN =>
26332671
atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt())) }
26342672
case QUOTE =>
2635-
simpleExpr()
2673+
simpleExpr(Location.ElseWhere)
26362674
case XMLSTART =>
26372675
xmlLiteralPattern()
26382676
case GIVEN =>
@@ -2649,6 +2687,8 @@ object Parsers {
26492687
}
26502688
}
26512689

2690+
val simplePatternFn: Location => Tree = _ => simplePattern()
2691+
26522692
def simplePatternRest(t: Tree): Tree =
26532693
if in.token == DOT then
26542694
in.nextToken()

docs/docs/internals/syntax.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,10 @@ SimpleExpr ::= SimpleRef
244244
| SimpleExpr ‘.’ MatchClause
245245
| SimpleExpr TypeArgs TypeApply(expr, args)
246246
| SimpleExpr ArgumentExprs Apply(expr, args)
247+
| SimpleExpr1 :<<< BlockExpr >>> -- under language.experimental.fewerBraces
248+
| SimpleExpr1 FunParams (‘=>’ | ‘?=>’) indent Block outdent -- under language.experimental.fewerBraces
247249
| SimpleExpr ‘_’ PostfixOp(expr, _) (to be dropped)
248-
| XmlExpr (to be dropped)
250+
| XmlExpr -- to be dropped
249251
Quoted ::= ‘'’ ‘{’ Block ‘}’
250252
| ‘'’ ‘[’ Type ‘]’
251253
ExprsInParens ::= ExprInParens {‘,’ ExprInParens}

tests/neg/closure-args.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
val x = List().map (x: => Int) => // error
2+
???
3+
val y = List() map x => // error
4+
x + 1 // error
5+
val z = List() map + => // error
6+
???
7+

tests/neg/i1779.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ object Test {
88
def f = {
99
val _parent = 3
1010
q"val hello = $_parent"
11-
q"class $_" // error // error
12-
} // error
11+
q"class $_" // error // error // error
12+
}
1313
}

tests/neg/i6059.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
def I0(I1: Int ) = I1
2-
val I1 = I0(I0 i2 // error
3-
) => true
2+
val I1 = I0(I0 i2) => // error
3+
true

tests/neg/i7751.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
val a = Some(a=a,)=> // error // error
1+
val a = Some(a=a,)=> // error // error // error
22
val a = Some(x=y,)=>

tests/pos/closure-args.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
val xs = List(1, 2, 3)
2+
val ys = xs.map x =>
3+
x + 1
4+
val x = ys.foldLeft(0) (x, y) =>
5+
x + y
6+
val y = ys.foldLeft(0) (x: Int, y: Int) =>
7+
val z = x + y
8+
z * z
9+
val as: Int = xs
10+
.map x =>
11+
x * x
12+
.filter y =>
13+
y > 0
14+
(0)

0 commit comments

Comments
 (0)