@@ -555,10 +555,29 @@ object Parsers {
555
555
accept(tok)
556
556
try body finally accept(tok + 1 )
557
557
558
+ /** Same as enclosed, but if closing token is missing, add `,` to the expected tokens
559
+ * in the error message provided the next token could have followed a `,`.
560
+ */
561
+ def enclosedWithCommas [T ](tok : Token , body : => T ): T =
562
+ accept(tok)
563
+ val closing = tok + 1
564
+ val isEmpty = in.token == closing
565
+ val ts = body
566
+ if in.token != closing then
567
+ val followComma =
568
+ if tok == LPAREN then canStartExprTokens3 else canStartTypeTokens
569
+ val prefix = if ! isEmpty && followComma.contains(in.token) then " ',' or " else " "
570
+ syntaxErrorOrIncomplete(ExpectedTokenButFound (closing, in.token, prefix))
571
+ if in.token == closing then in.nextToken()
572
+ ts
573
+
558
574
def inParens [T ](body : => T ): T = enclosed(LPAREN , body)
559
575
def inBraces [T ](body : => T ): T = enclosed(LBRACE , body)
560
576
def inBrackets [T ](body : => T ): T = enclosed(LBRACKET , body)
561
577
578
+ def inParensWithCommas [T ](body : => T ): T = enclosedWithCommas(LPAREN , body)
579
+ def inBracketsWithCommas [T ](body : => T ): T = enclosedWithCommas(LBRACKET , body)
580
+
562
581
def inBracesOrIndented [T ](body : => T , rewriteWithColon : Boolean = false ): T =
563
582
if in.token == INDENT then
564
583
val rewriteToBraces = in.rewriteNoIndent
@@ -970,6 +989,17 @@ object Parsers {
970
989
isArrowIndent()
971
990
else false
972
991
992
+ /** Can the next lookahead token start an operand as defined by
993
+ * leadingOperandTokens, or is postfix ops enabled?
994
+ * This is used to decide whether the current token can be an infix operator.
995
+ */
996
+ def nextCanFollowOperator (leadingOperandTokens : BitSet ): Boolean =
997
+ leadingOperandTokens.contains(in.lookahead.token)
998
+ || in.postfixOpsEnabled
999
+ || in.lookahead.token == COLONop
1000
+ || in.lookahead.token == EOF // important for REPL completions
1001
+ || ctx.mode.is(Mode .Interactive ) // in interactive mode the next tokens might be missing
1002
+
973
1003
/* --------- OPERAND/OPERATOR STACK --------------------------------------- */
974
1004
975
1005
var opStack : List [OpInfo ] = Nil
@@ -1050,7 +1080,11 @@ object Parsers {
1050
1080
then recur(top)
1051
1081
else top
1052
1082
1053
- recur(first)
1083
+ val res = recur(first)
1084
+ if isIdent(nme.raw.STAR ) && ! followingIsVararg() then
1085
+ syntaxError(em " spread operator `*` not allowed here; must come last in a parameter list " )
1086
+ in.nextToken()
1087
+ res
1054
1088
end infixOps
1055
1089
1056
1090
/* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */
@@ -1659,7 +1693,7 @@ object Parsers {
1659
1693
/** FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
1660
1694
*/
1661
1695
def funParamClause (): List [ValDef ] =
1662
- inParens (commaSeparated(() => typedFunParam(in.offset, ident())))
1696
+ inParensWithCommas (commaSeparated(() => typedFunParam(in.offset, ident())))
1663
1697
1664
1698
def funParamClauses (): List [List [ValDef ]] =
1665
1699
if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
@@ -1671,7 +1705,8 @@ object Parsers {
1671
1705
1672
1706
def infixTypeRest (t : Tree ): Tree =
1673
1707
infixOps(t, canStartInfixTypeTokens, refinedTypeFn, Location .ElseWhere , ParseKind .Type ,
1674
- isOperator = ! followingIsVararg() && ! isPureArrow)
1708
+ isOperator = ! followingIsVararg() && ! isPureArrow
1709
+ && nextCanFollowOperator(canStartInfixTypeTokens))
1675
1710
1676
1711
/** RefinedType ::= WithType {[nl] Refinement} [`^` CaptureSet]
1677
1712
*/
@@ -1807,7 +1842,7 @@ object Parsers {
1807
1842
else
1808
1843
def singletonArgs (t : Tree ): Tree =
1809
1844
if in.token == LPAREN && in.featureEnabled(Feature .dependent)
1810
- then singletonArgs(AppliedTypeTree (t, inParens (commaSeparated(singleton))))
1845
+ then singletonArgs(AppliedTypeTree (t, inParensWithCommas (commaSeparated(singleton))))
1811
1846
else t
1812
1847
singletonArgs(simpleType1())
1813
1848
@@ -1823,7 +1858,7 @@ object Parsers {
1823
1858
def simpleType1 () = simpleTypeRest {
1824
1859
if in.token == LPAREN then
1825
1860
atSpan(in.offset) {
1826
- makeTupleOrParens(inParens (argTypes(namedOK = false , wildOK = true )))
1861
+ makeTupleOrParens(inParensWithCommas (argTypes(namedOK = false , wildOK = true )))
1827
1862
}
1828
1863
else if in.token == LBRACE then
1829
1864
atSpan(in.offset) { RefinedTypeTree (EmptyTree , refinement(indentOK = false )) }
@@ -1976,7 +2011,8 @@ object Parsers {
1976
2011
/** TypeArgs ::= `[' Type {`,' Type} `]'
1977
2012
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
1978
2013
*/
1979
- def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] = inBrackets(argTypes(namedOK, wildOK))
2014
+ def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] =
2015
+ inBracketsWithCommas(argTypes(namedOK, wildOK))
1980
2016
1981
2017
/** Refinement ::= `{' RefineStatSeq `}'
1982
2018
*/
@@ -2413,7 +2449,8 @@ object Parsers {
2413
2449
2414
2450
def postfixExprRest (t : Tree , location : Location ): Tree =
2415
2451
infixOps(t, in.canStartExprTokens, prefixExpr, location, ParseKind .Expr ,
2416
- isOperator = ! (location.inArgs && followingIsVararg()))
2452
+ isOperator = ! (location.inArgs && followingIsVararg())
2453
+ && nextCanFollowOperator(canStartInfixExprTokens))
2417
2454
2418
2455
/** PrefixExpr ::= [PrefixOperator'] SimpleExpr
2419
2456
* PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ (if not backquoted)
@@ -2472,7 +2509,7 @@ object Parsers {
2472
2509
placeholderParams = param :: placeholderParams
2473
2510
atSpan(start) { Ident (pname) }
2474
2511
case LPAREN =>
2475
- atSpan(in.offset) { makeTupleOrParens(inParens (exprsInParensOrBindings())) }
2512
+ atSpan(in.offset) { makeTupleOrParens(inParensWithCommas (exprsInParensOrBindings())) }
2476
2513
case LBRACE | INDENT =>
2477
2514
canApply = false
2478
2515
blockExpr()
@@ -2577,15 +2614,15 @@ object Parsers {
2577
2614
/** ParArgumentExprs ::= `(' [‘using’] [ExprsInParens] `)'
2578
2615
* | `(' [ExprsInParens `,'] PostfixExpr `*' ')'
2579
2616
*/
2580
- def parArgumentExprs (): (List [Tree ], Boolean ) = inParens {
2581
- if in.token == RPAREN then
2582
- ( Nil , false )
2583
- else if isIdent(nme.using) then
2584
- in.nextToken()
2585
- (commaSeparated(argumentExpr), true )
2586
- else
2587
- (commaSeparated(argumentExpr), false )
2588
- }
2617
+ def parArgumentExprs (): (List [Tree ], Boolean ) =
2618
+ inParensWithCommas :
2619
+ if in.token == RPAREN then
2620
+ ( Nil , false )
2621
+ else if isIdent(nme.using) then
2622
+ in.nextToken( )
2623
+ (commaSeparated(argumentExpr), true )
2624
+ else
2625
+ (commaSeparated(argumentExpr), false )
2589
2626
2590
2627
/** ArgumentExprs ::= ParArgumentExprs
2591
2628
* | [nl] BlockExpr
@@ -2920,7 +2957,8 @@ object Parsers {
2920
2957
def infixPattern (): Tree =
2921
2958
infixOps(
2922
2959
simplePattern(), in.canStartExprTokens, simplePatternFn, Location .InPattern , ParseKind .Pattern ,
2923
- isOperator = in.name != nme.raw.BAR && ! followingIsVararg())
2960
+ isOperator = in.name != nme.raw.BAR && ! followingIsVararg()
2961
+ && nextCanFollowOperator(canStartPatternTokens))
2924
2962
2925
2963
/** SimplePattern ::= PatVar
2926
2964
* | Literal
@@ -2941,7 +2979,7 @@ object Parsers {
2941
2979
case USCORE =>
2942
2980
wildcardIdent()
2943
2981
case LPAREN =>
2944
- atSpan(in.offset) { makeTupleOrParens(inParens (patternsOpt())) }
2982
+ atSpan(in.offset) { makeTupleOrParens(inParensWithCommas (patternsOpt())) }
2945
2983
case QUOTE =>
2946
2984
simpleExpr(Location .InPattern )
2947
2985
case XMLSTART =>
@@ -2987,7 +3025,7 @@ object Parsers {
2987
3025
* | ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
2988
3026
*/
2989
3027
def argumentPatterns (): List [Tree ] =
2990
- inParens (patternsOpt(Location .InPatternArgs ))
3028
+ inParensWithCommas (patternsOpt(Location .InPatternArgs ))
2991
3029
2992
3030
/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */
2993
3031
@@ -3176,7 +3214,7 @@ object Parsers {
3176
3214
* HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
3177
3215
* HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypePamClause] | ‘_’) TypeBounds
3178
3216
*/
3179
- def typeParamClause (ownerKind : ParamOwner ): List [TypeDef ] = inBrackets {
3217
+ def typeParamClause (ownerKind : ParamOwner ): List [TypeDef ] = inBracketsWithCommas {
3180
3218
3181
3219
def checkVarianceOK (): Boolean =
3182
3220
val ok = ownerKind != ParamOwner .Def && ownerKind != ParamOwner .TypeParam
@@ -3315,7 +3353,7 @@ object Parsers {
3315
3353
}
3316
3354
3317
3355
// begin termParamClause
3318
- inParens {
3356
+ inParensWithCommas {
3319
3357
if in.token == RPAREN && ! prefix && ! impliedMods.is(Given ) then Nil
3320
3358
else
3321
3359
val clause =
0 commit comments