@@ -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
*/
@@ -1839,7 +1874,7 @@ object Parsers {
1839
1874
else
1840
1875
def singletonArgs (t : Tree ): Tree =
1841
1876
if in.token == LPAREN && in.featureEnabled(Feature .dependent)
1842
- then singletonArgs(AppliedTypeTree (t, inParens (commaSeparated(singleton))))
1877
+ then singletonArgs(AppliedTypeTree (t, inParensWithCommas (commaSeparated(singleton))))
1843
1878
else t
1844
1879
singletonArgs(simpleType1())
1845
1880
@@ -1855,7 +1890,7 @@ object Parsers {
1855
1890
def simpleType1 () = simpleTypeRest {
1856
1891
if in.token == LPAREN then
1857
1892
atSpan(in.offset) {
1858
- makeTupleOrParens(inParens (argTypes(namedOK = false , wildOK = true )))
1893
+ makeTupleOrParens(inParensWithCommas (argTypes(namedOK = false , wildOK = true )))
1859
1894
}
1860
1895
else if in.token == LBRACE then
1861
1896
atSpan(in.offset) { RefinedTypeTree (EmptyTree , refinement(indentOK = false )) }
@@ -2008,7 +2043,8 @@ object Parsers {
2008
2043
/** TypeArgs ::= `[' Type {`,' Type} `]'
2009
2044
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
2010
2045
*/
2011
- def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] = inBrackets(argTypes(namedOK, wildOK))
2046
+ def typeArgs (namedOK : Boolean , wildOK : Boolean ): List [Tree ] =
2047
+ inBracketsWithCommas(argTypes(namedOK, wildOK))
2012
2048
2013
2049
/** Refinement ::= `{' RefineStatSeq `}'
2014
2050
*/
@@ -2444,7 +2480,8 @@ object Parsers {
2444
2480
2445
2481
def postfixExprRest (t : Tree , location : Location ): Tree =
2446
2482
infixOps(t, in.canStartExprTokens, prefixExpr, location, ParseKind .Expr ,
2447
- isOperator = ! (location.inArgs && followingIsVararg()))
2483
+ isOperator = ! (location.inArgs && followingIsVararg())
2484
+ && nextCanFollowOperator(canStartInfixExprTokens))
2448
2485
2449
2486
/** PrefixExpr ::= [PrefixOperator'] SimpleExpr
2450
2487
* PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ (if not backquoted)
@@ -2503,7 +2540,7 @@ object Parsers {
2503
2540
placeholderParams = param :: placeholderParams
2504
2541
atSpan(start) { Ident (pname) }
2505
2542
case LPAREN =>
2506
- atSpan(in.offset) { makeTupleOrParens(inParens (exprsInParensOrBindings())) }
2543
+ atSpan(in.offset) { makeTupleOrParens(inParensWithCommas (exprsInParensOrBindings())) }
2507
2544
case LBRACE | INDENT =>
2508
2545
canApply = false
2509
2546
blockExpr()
@@ -2601,15 +2638,15 @@ object Parsers {
2601
2638
/** ParArgumentExprs ::= `(' [‘using’] [ExprsInParens] `)'
2602
2639
* | `(' [ExprsInParens `,'] PostfixExpr `*' ')'
2603
2640
*/
2604
- def parArgumentExprs (): (List [Tree ], Boolean ) = inParens {
2605
- if in.token == RPAREN then
2606
- ( Nil , false )
2607
- else if isIdent(nme.using) then
2608
- in.nextToken()
2609
- (commaSeparated(argumentExpr), true )
2610
- else
2611
- (commaSeparated(argumentExpr), false )
2612
- }
2641
+ def parArgumentExprs (): (List [Tree ], Boolean ) =
2642
+ inParensWithCommas :
2643
+ if in.token == RPAREN then
2644
+ ( Nil , false )
2645
+ else if isIdent(nme.using) then
2646
+ in.nextToken( )
2647
+ (commaSeparated(argumentExpr), true )
2648
+ else
2649
+ (commaSeparated(argumentExpr), false )
2613
2650
2614
2651
/** ArgumentExprs ::= ParArgumentExprs
2615
2652
* | [nl] BlockExpr
@@ -2947,7 +2984,8 @@ object Parsers {
2947
2984
def infixPattern (): Tree =
2948
2985
infixOps(
2949
2986
simplePattern(), in.canStartExprTokens, simplePatternFn, Location .InPattern , ParseKind .Pattern ,
2950
- isOperator = in.name != nme.raw.BAR && ! followingIsVararg())
2987
+ isOperator = in.name != nme.raw.BAR && ! followingIsVararg()
2988
+ && nextCanFollowOperator(canStartPatternTokens))
2951
2989
2952
2990
/** SimplePattern ::= PatVar
2953
2991
* | Literal
@@ -2969,7 +3007,7 @@ object Parsers {
2969
3007
case USCORE =>
2970
3008
wildcardIdent()
2971
3009
case LPAREN =>
2972
- atSpan(in.offset) { makeTupleOrParens(inParens (patternsOpt())) }
3010
+ atSpan(in.offset) { makeTupleOrParens(inParensWithCommas (patternsOpt())) }
2973
3011
case QUOTE =>
2974
3012
simpleExpr(Location .InPattern )
2975
3013
case XMLSTART =>
@@ -3015,7 +3053,7 @@ object Parsers {
3015
3053
* | ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
3016
3054
*/
3017
3055
def argumentPatterns (): List [Tree ] =
3018
- inParens (patternsOpt(Location .InPatternArgs ))
3056
+ inParensWithCommas (patternsOpt(Location .InPatternArgs ))
3019
3057
3020
3058
/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */
3021
3059
@@ -3204,7 +3242,7 @@ object Parsers {
3204
3242
* HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
3205
3243
* HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypePamClause] | ‘_’) TypeBounds
3206
3244
*/
3207
- def typeParamClause (ownerKind : ParamOwner ): List [TypeDef ] = inBrackets {
3245
+ def typeParamClause (ownerKind : ParamOwner ): List [TypeDef ] = inBracketsWithCommas {
3208
3246
3209
3247
def checkVarianceOK (): Boolean =
3210
3248
val ok = ownerKind != ParamOwner .Def && ownerKind != ParamOwner .TypeParam
@@ -3344,7 +3382,7 @@ object Parsers {
3344
3382
}
3345
3383
3346
3384
// begin termParamClause
3347
- inParens {
3385
+ inParensWithCommas {
3348
3386
if in.token == RPAREN && ! prefix && ! impliedMods.is(Given ) then Nil
3349
3387
else
3350
3388
val clause =
0 commit comments