@@ -43,6 +43,7 @@ object Parsers {
4343 enum Location (val inParens : Boolean , val inPattern : Boolean , val inArgs : Boolean ):
4444 case InParens extends Location (true , false , false )
4545 case InArgs extends Location (true , false , true )
46+ case InColonArg extends Location (false , false , true )
4647 case InPattern extends Location (false , true , false )
4748 case InGuard extends Location (false , false , false )
4849 case InPatternArgs extends Location (false , true , true ) // InParens not true, since it might be an alternative
@@ -431,7 +432,7 @@ object Parsers {
431432 convertToParam(t, mods) :: Nil
432433 case Tuple (ts) =>
433434 ts.map(convertToParam(_, mods))
434- case t : Typed =>
435+ case t @ Typed ( Ident (_), _) =>
435436 report.errorOrMigrationWarning(
436437 em " parentheses are required around the parameter of a lambda ${rewriteNotice()}" ,
437438 in.sourcePos(), from = `3.0`)
@@ -444,20 +445,24 @@ object Parsers {
444445
445446 /** Convert tree to formal parameter
446447 */
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)
459451 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()
461466
462467 /** Convert (qual)ident to type identifier
463468 */
@@ -891,9 +896,8 @@ object Parsers {
891896 val next = in.lookahead.token
892897 next == LBRACKET || next == LPAREN
893898
894-
895899 def followingIsSelfType () =
896- val lookahead = in.LookaheadScanner ()
900+ val lookahead = in.LookaheadScanner (allowIndent = true )
897901 lookahead.nextToken()
898902 lookahead.token == COLON
899903 && {
@@ -915,6 +919,43 @@ object Parsers {
915919 }
916920 }
917921
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+
918959 /* --------- OPERAND/OPERATOR STACK --------------------------------------- */
919960
920961 var opStack : List [OpInfo ] = Nil
@@ -2209,7 +2250,11 @@ object Parsers {
22092250 in.nextToken()
22102251 else
22112252 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)
22132258 }
22142259
22152260 /** PostfixExpr ::= InfixExpr [id [nl]]
@@ -2259,9 +2304,11 @@ object Parsers {
22592304 * | SimpleExpr `.` MatchClause
22602305 * | SimpleExpr (TypeArgs | NamedTypeArgs)
22612306 * | 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
22652312 * Quoted ::= ‘'’ ‘{’ Block ‘}’
22662313 * | ‘'’ ‘[’ Type ‘]’
22672314 */
@@ -2283,7 +2330,7 @@ object Parsers {
22832330 placeholderParams = param :: placeholderParams
22842331 atSpan(start) { Ident (pname) }
22852332 case LPAREN =>
2286- atSpan(in.offset) { makeTupleOrParens(inParens(exprsInParensOpt ())) }
2333+ atSpan(in.offset) { makeTupleOrParens(inParens(exprsInParensOrBindings ())) }
22872334 case LBRACE | INDENT =>
22882335 canApply = false
22892336 blockExpr()
@@ -2317,55 +2364,38 @@ object Parsers {
23172364 simpleExprRest(t, location, canApply)
23182365 }
23192366
2320- def simpleExprRest (t : Tree , location : Location , canApply : Boolean = true ): Tree = {
2367+ def simpleExprRest (t : Tree , location : Location , canApply : Boolean = true ): Tree =
23212368 if (canApply) argumentStart()
2322- in.token match {
2369+ in.token match
23232370 case DOT =>
23242371 in.nextToken()
23252372 simpleExprRest(selectorOrMatch(t), location, canApply = true )
23262373 case LBRACKET =>
23272374 val tapp = atSpan(startOffset(t), in.offset) { TypeApply (t, typeArgs(namedOK = true , wildOK = false )) }
23282375 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 =>
23432377 val app = atSpan(startOffset(t), in.offset) { mkApply(t, argumentExprs()) }
23442378 simpleExprRest(app, location, canApply = true )
23452379 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 )) }
23552381 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
23692399
23702400 /** SimpleExpr ::= ‘new’ ConstrApp {`with` ConstrApp} [TemplateBody]
23712401 * | ‘new’ TemplateBody
@@ -2387,9 +2417,20 @@ object Parsers {
23872417 }
23882418
23892419 /** ExprsInParens ::= ExprInParens {`,' ExprInParens}
2420+ * Bindings ::= Binding {`,' Binding}
23902421 */
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+ }
23932434
23942435 /** ParArgumentExprs ::= `(' [‘using’] [ExprsInParens] `)'
23952436 * | `(' [ExprsInParens `,'] PostfixExpr `*' ')'
0 commit comments