@@ -43,6 +43,7 @@ object Parsers {
43
43
enum Location (val inParens : Boolean , val inPattern : Boolean , val inArgs : Boolean ):
44
44
case InParens extends Location (true , false , false )
45
45
case InArgs extends Location (true , false , true )
46
+ case InColonArg extends Location (false , false , true )
46
47
case InPattern extends Location (false , true , false )
47
48
case InGuard extends Location (false , false , false )
48
49
case InPatternArgs extends Location (false , true , true ) // InParens not true, since it might be an alternative
@@ -431,7 +432,7 @@ object Parsers {
431
432
convertToParam(t, mods) :: Nil
432
433
case Tuple (ts) =>
433
434
ts.map(convertToParam(_, mods))
434
- case t : Typed =>
435
+ case t @ Typed ( Ident (_), _) =>
435
436
report.errorOrMigrationWarning(
436
437
em " parentheses are required around the parameter of a lambda ${rewriteNotice()}" ,
437
438
in.sourcePos(), from = `3.0`)
@@ -444,20 +445,24 @@ object Parsers {
444
445
445
446
/** Convert tree to formal parameter
446
447
*/
447
- def convertToParam (tree : Tree , mods : Modifiers , expected : String = " formal parameter" ): ValDef = tree match {
448
- case id @ Ident (name) =>
449
- makeParameter(name.asTermName, TypeTree (), mods, isBackquoted = isBackquoted(id)).withSpan(tree.span)
450
- case Typed (_, tpt : TypeBoundsTree ) =>
451
- syntaxError(s " not a legal $expected" , tree.span)
452
- makeParameter(nme.ERROR , tree, mods)
453
- case Typed (id @ Ident (name), tpt) =>
454
- makeParameter(name.asTermName, tpt, mods, isBackquoted = isBackquoted(id)).withSpan(tree.span)
455
- case Typed (Splice (Ident (name)), tpt) =>
456
- makeParameter((" $" + name).toTermName, tpt, mods).withSpan(tree.span)
457
- case _ =>
458
- syntaxError(s " not a legal $expected" , tree.span)
448
+ def convertToParam (tree : Tree , mods : Modifiers ): ValDef =
449
+ def fail () =
450
+ syntaxError(s " not a legal formal parameter for a function literal " , tree.span)
459
451
makeParameter(nme.ERROR , tree, mods)
460
- }
452
+ tree match
453
+ case param : ValDef =>
454
+ param.withMods(param.mods | mods.flags)
455
+ case id @ Ident (name) =>
456
+ makeParameter(name.asTermName, TypeTree (), mods, isBackquoted = isBackquoted(id)).withSpan(tree.span)
457
+ // the following three cases are needed only for 2.x parameters without enclosing parentheses
458
+ case Typed (_, tpt : TypeBoundsTree ) =>
459
+ fail()
460
+ case Typed (id @ Ident (name), tpt) =>
461
+ makeParameter(name.asTermName, tpt, mods, isBackquoted = isBackquoted(id)).withSpan(tree.span)
462
+ case Typed (Splice (Ident (name)), tpt) =>
463
+ makeParameter((" $" + name).toTermName, tpt, mods).withSpan(tree.span)
464
+ case _ =>
465
+ fail()
461
466
462
467
/** Convert (qual)ident to type identifier
463
468
*/
@@ -891,9 +896,8 @@ object Parsers {
891
896
val next = in.lookahead.token
892
897
next == LBRACKET || next == LPAREN
893
898
894
-
895
899
def followingIsSelfType () =
896
- val lookahead = in.LookaheadScanner ()
900
+ val lookahead = in.LookaheadScanner (allowIndent = true )
897
901
lookahead.nextToken()
898
902
lookahead.token == COLON
899
903
&& {
@@ -915,6 +919,43 @@ object Parsers {
915
919
}
916
920
}
917
921
922
+ /** When encountering a `:`, is that in the binding of a lambda?
923
+ * @pre location of the enclosing expression is `InParens`, so there is an open `(`.
924
+ */
925
+ def followingIsLambdaParams () =
926
+ val lookahead = in.LookaheadScanner ()
927
+ lookahead.nextToken()
928
+ while lookahead.token != RPAREN && lookahead.token != EOF do
929
+ if lookahead.token == LPAREN then lookahead.skipParens()
930
+ else lookahead.nextToken()
931
+ lookahead.token == RPAREN
932
+ && {
933
+ lookahead.nextToken()
934
+ lookahead.isArrow
935
+ }
936
+
937
+ /** Is the token sequence following the current `:` token classified as a lambda?
938
+ * This is the case if the input starts with an identifier, a wildcard, or
939
+ * something enclosed in (...) or [...], and this is followed by a `=>` or `?=>`
940
+ * and an INDENT.
941
+ */
942
+ def followingIsLambdaAfterColon (): Boolean =
943
+ val lookahead = in.LookaheadScanner (allowIndent = true )
944
+ def isArrowIndent () =
945
+ lookahead.isArrow
946
+ && {
947
+ lookahead.nextToken()
948
+ lookahead.token == INDENT
949
+ }
950
+ lookahead.nextToken()
951
+ if lookahead.isIdent || lookahead.token == USCORE then
952
+ lookahead.nextToken()
953
+ isArrowIndent()
954
+ else if lookahead.token == LPAREN || lookahead.token == LBRACKET then
955
+ lookahead.skipParens()
956
+ isArrowIndent()
957
+ else false
958
+
918
959
/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
919
960
920
961
var opStack : List [OpInfo ] = Nil
@@ -2209,7 +2250,11 @@ object Parsers {
2209
2250
in.nextToken()
2210
2251
else
2211
2252
accept(ARROW )
2212
- Function (params, if (location == Location .InBlock ) block() else expr())
2253
+ val body =
2254
+ if location == Location .InBlock then block()
2255
+ else if location == Location .InColonArg && in.token == INDENT then blockExpr()
2256
+ else expr()
2257
+ Function (params, body)
2213
2258
}
2214
2259
2215
2260
/** PostfixExpr ::= InfixExpr [id [nl]]
@@ -2259,9 +2304,11 @@ object Parsers {
2259
2304
* | SimpleExpr `.` MatchClause
2260
2305
* | SimpleExpr (TypeArgs | NamedTypeArgs)
2261
2306
* | SimpleExpr1 ArgumentExprs
2262
- * | SimpleExpr1 `:` IndentedExpr -- under language.experimental.fewerBraces
2263
- * | SimpleExpr1 FunParams (‘=>’ | ‘?=>’) IndentedExpr -- under language.experimental.fewerBraces
2264
- * IndentedExpr ::= indent (CaseClauses | Block) outdent
2307
+ * | SimpleExpr1 `:` ColonArgument -- under language.experimental.fewerBraces
2308
+ * ColonArgument ::= indent (CaseClauses | Block) outdent
2309
+ * | FunParams (‘=>’ | ‘?=>’) ColonArgBody
2310
+ * | HkTypeParamClause ‘=>’ ColonArgBody
2311
+ * ColonArgBody ::= indent (CaseClauses | Block) outdent
2265
2312
* Quoted ::= ‘'’ ‘{’ Block ‘}’
2266
2313
* | ‘'’ ‘[’ Type ‘]’
2267
2314
*/
@@ -2283,7 +2330,7 @@ object Parsers {
2283
2330
placeholderParams = param :: placeholderParams
2284
2331
atSpan(start) { Ident (pname) }
2285
2332
case LPAREN =>
2286
- atSpan(in.offset) { makeTupleOrParens(inParens(exprsInParensOpt ())) }
2333
+ atSpan(in.offset) { makeTupleOrParens(inParens(exprsInParensOrBindings ())) }
2287
2334
case LBRACE | INDENT =>
2288
2335
canApply = false
2289
2336
blockExpr()
@@ -2317,55 +2364,38 @@ object Parsers {
2317
2364
simpleExprRest(t, location, canApply)
2318
2365
}
2319
2366
2320
- def simpleExprRest (t : Tree , location : Location , canApply : Boolean = true ): Tree = {
2367
+ def simpleExprRest (t : Tree , location : Location , canApply : Boolean = true ): Tree =
2321
2368
if (canApply) argumentStart()
2322
- in.token match {
2369
+ in.token match
2323
2370
case DOT =>
2324
2371
in.nextToken()
2325
2372
simpleExprRest(selectorOrMatch(t), location, canApply = true )
2326
2373
case LBRACKET =>
2327
2374
val tapp = atSpan(startOffset(t), in.offset) { TypeApply (t, typeArgs(namedOK = true , wildOK = false )) }
2328
2375
simpleExprRest(tapp, location, canApply = true )
2329
- case LPAREN if canApply =>
2330
- val app = atSpan(startOffset(t), in.offset) {
2331
- val argExprs @ (args, isUsing) = argumentExprs()
2332
- if ! isUsing && in.isArrow && location != Location .InGuard && in.fewerBracesEnabled then
2333
- val params = convertToParams(Tuple (args))
2334
- if params.forall(_.name != nme.ERROR ) then
2335
- applyToClosure(t, in.offset, params)
2336
- else
2337
- mkApply(t, argExprs)
2338
- else
2339
- mkApply(t, argExprs)
2340
- }
2341
- simpleExprRest(app, location, canApply = true )
2342
- case LBRACE | INDENT if canApply =>
2376
+ case LPAREN | LBRACE | INDENT if canApply =>
2343
2377
val app = atSpan(startOffset(t), in.offset) { mkApply(t, argumentExprs()) }
2344
2378
simpleExprRest(app, location, canApply = true )
2345
2379
case USCORE =>
2346
- if in.lookahead.isArrow && location != Location .InGuard && in.fewerBracesEnabled then
2347
- val app = applyToClosure(t, in.offset, convertToParams(wildcardIdent()))
2348
- simpleExprRest(app, location, canApply = true )
2349
- else
2350
- atSpan(startOffset(t), in.skipToken()) { PostfixOp (t, Ident (nme.WILDCARD )) }
2351
- case IDENTIFIER
2352
- if ! in.isOperator && in.lookahead.isArrow && location != Location .InGuard && in.fewerBracesEnabled =>
2353
- val app = applyToClosure(t, in.offset, convertToParams(termIdent()))
2354
- simpleExprRest(app, location, canApply = true )
2380
+ atSpan(startOffset(t), in.skipToken()) { PostfixOp (t, Ident (nme.WILDCARD )) }
2355
2381
case _ =>
2356
- t
2357
- }
2358
- }
2359
-
2360
- def applyToClosure (t : Tree , start : Offset , params : List [ValDef ]): Tree =
2361
- atSpan(startOffset(t), in.offset) {
2362
- val arg = atSpan(start, in.skipToken()) {
2363
- if in.token != INDENT then
2364
- syntaxErrorOrIncomplete(i " indented expression expected, ${in} found " )
2365
- Function (params, blockExpr())
2366
- }
2367
- Apply (t, arg)
2368
- }
2382
+ if in.isColon() && location == Location .InParens && followingIsLambdaParams() then
2383
+ t match
2384
+ case id @ Ident (name) =>
2385
+ if name.is(WildcardParamName ) then
2386
+ assert(name == placeholderParams.head.name)
2387
+ placeholderParams = placeholderParams.tail
2388
+ atSpan(startOffset(id)) {
2389
+ makeParameter(name.asTermName, typedOpt(), Modifiers (), isBackquoted = isBackquoted(id))
2390
+ }
2391
+ case _ => t
2392
+ else if in.fewerBracesEnabled && in.token == COLON && followingIsLambdaAfterColon() then
2393
+ val app = atSpan(startOffset(t), in.skipToken()) {
2394
+ Apply (t, expr(Location .InColonArg ) :: Nil )
2395
+ }
2396
+ simpleExprRest(app, location, canApply = true )
2397
+ else t
2398
+ end simpleExprRest
2369
2399
2370
2400
/** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody]
2371
2401
* | ‘new’ TemplateBody
@@ -2387,9 +2417,20 @@ object Parsers {
2387
2417
}
2388
2418
2389
2419
/** ExprsInParens ::= ExprInParens {`,' ExprInParens}
2420
+ * Bindings ::= Binding {`,' Binding}
2390
2421
*/
2391
- def exprsInParensOpt (): List [Tree ] =
2392
- if (in.token == RPAREN ) Nil else commaSeparated(exprInParens)
2422
+ def exprsInParensOrBindings (): List [Tree ] =
2423
+ if in.token == RPAREN then Nil
2424
+ else in.currentRegion.withCommasExpected {
2425
+ var isFormalParams = false
2426
+ def exprOrBinding () =
2427
+ if isFormalParams then binding(Modifiers ())
2428
+ else
2429
+ val t = exprInParens()
2430
+ if t.isInstanceOf [ValDef ] then isFormalParams = true
2431
+ t
2432
+ commaSeparatedRest(exprOrBinding(), exprOrBinding)
2433
+ }
2393
2434
2394
2435
/** ParArgumentExprs ::= `(' [‘using’] [ExprsInParens] `)'
2395
2436
* | `(' [ExprsInParens `,'] PostfixExpr `*' ')'
0 commit comments