@@ -555,10 +555,29 @@ object Parsers {
555555 accept(tok)
556556 try body finally accept(tok + 1 )
557557
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+
558574 def inParens [T ](body : => T ): T = enclosed(LPAREN , body)
559575 def inBraces [T ](body : => T ): T = enclosed(LBRACE , body)
560576 def inBrackets [T ](body : => T ): T = enclosed(LBRACKET , body)
561577
578+ def inParensWithCommas [T ](body : => T ): T = enclosedWithCommas(LPAREN , body)
579+ def inBracketsWithCommas [T ](body : => T ): T = enclosedWithCommas(LBRACKET , body)
580+
562581 def inBracesOrIndented [T ](body : => T , rewriteWithColon : Boolean = false ): T =
563582 if in.token == INDENT then
564583 val rewriteToBraces = in.rewriteNoIndent
@@ -970,6 +989,17 @@ object Parsers {
970989 isArrowIndent()
971990 else false
972991
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+
9731003 /* --------- OPERAND/OPERATOR STACK --------------------------------------- */
9741004
9751005 var opStack : List [OpInfo ] = Nil
@@ -1050,7 +1080,11 @@ object Parsers {
10501080 then recur(top)
10511081 else top
10521082
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
10541088 end infixOps
10551089
10561090/* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */
@@ -1659,7 +1693,7 @@ object Parsers {
16591693 /** FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
16601694 */
16611695 def funParamClause (): List [ValDef ] =
1662- inParens (commaSeparated(() => typedFunParam(in.offset, ident())))
1696+ inParensWithCommas (commaSeparated(() => typedFunParam(in.offset, ident())))
16631697
16641698 def funParamClauses (): List [List [ValDef ]] =
16651699 if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
@@ -1671,7 +1705,8 @@ object Parsers {
16711705
16721706 def infixTypeRest (t : Tree ): Tree =
16731707 infixOps(t, canStartInfixTypeTokens, refinedTypeFn, Location .ElseWhere , ParseKind .Type ,
1674- isOperator = ! followingIsVararg() && ! isPureArrow)
1708+ isOperator = ! followingIsVararg() && ! isPureArrow
1709+ && nextCanFollowOperator(canStartInfixTypeTokens))
16751710
16761711 /** RefinedType ::= WithType {[nl] Refinement} [`^` CaptureSet]
16771712 */
@@ -1839,7 +1874,7 @@ object Parsers {
18391874 else
18401875 def singletonArgs (t : Tree ): Tree =
18411876 if in.token == LPAREN && in.featureEnabled(Feature .dependent)
1842- then singletonArgs(AppliedTypeTree (t, inParens (commaSeparated(singleton))))
1877+ then singletonArgs(AppliedTypeTree (t, inParensWithCommas (commaSeparated(singleton))))
18431878 else t
18441879 singletonArgs(simpleType1())
18451880
@@ -1855,7 +1890,7 @@ object Parsers {
18551890 def simpleType1 () = simpleTypeRest {
18561891 if in.token == LPAREN then
18571892 atSpan(in.offset) {
1858- makeTupleOrParens(inParens (argTypes(namedOK = false , wildOK = true )))
1893+ makeTupleOrParens(inParensWithCommas (argTypes(namedOK = false , wildOK = true )))
18591894 }
18601895 else if in.token == LBRACE then
18611896 atSpan(in.offset) { RefinedTypeTree (EmptyTree , refinement(indentOK = false )) }
@@ -2008,7 +2043,8 @@ object Parsers {
20082043 /** TypeArgs ::= `[' Type {`,' Type} `]'
20092044 * NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
20102045 */
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))
20122048
20132049 /** Refinement ::= `{' RefineStatSeq `}'
20142050 */
@@ -2444,7 +2480,8 @@ object Parsers {
24442480
24452481 def postfixExprRest (t : Tree , location : Location ): Tree =
24462482 infixOps(t, in.canStartExprTokens, prefixExpr, location, ParseKind .Expr ,
2447- isOperator = ! (location.inArgs && followingIsVararg()))
2483+ isOperator = ! (location.inArgs && followingIsVararg())
2484+ && nextCanFollowOperator(canStartInfixExprTokens))
24482485
24492486 /** PrefixExpr ::= [PrefixOperator'] SimpleExpr
24502487 * PrefixOperator ::= ‘-’ | ‘+’ | ‘~’ | ‘!’ (if not backquoted)
@@ -2503,7 +2540,7 @@ object Parsers {
25032540 placeholderParams = param :: placeholderParams
25042541 atSpan(start) { Ident (pname) }
25052542 case LPAREN =>
2506- atSpan(in.offset) { makeTupleOrParens(inParens (exprsInParensOrBindings())) }
2543+ atSpan(in.offset) { makeTupleOrParens(inParensWithCommas (exprsInParensOrBindings())) }
25072544 case LBRACE | INDENT =>
25082545 canApply = false
25092546 blockExpr()
@@ -2601,15 +2638,15 @@ object Parsers {
26012638 /** ParArgumentExprs ::= `(' [‘using’] [ExprsInParens] `)'
26022639 * | `(' [ExprsInParens `,'] PostfixExpr `*' ')'
26032640 */
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 )
26132650
26142651 /** ArgumentExprs ::= ParArgumentExprs
26152652 * | [nl] BlockExpr
@@ -2947,7 +2984,8 @@ object Parsers {
29472984 def infixPattern (): Tree =
29482985 infixOps(
29492986 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))
29512989
29522990 /** SimplePattern ::= PatVar
29532991 * | Literal
@@ -2969,7 +3007,7 @@ object Parsers {
29693007 case USCORE =>
29703008 wildcardIdent()
29713009 case LPAREN =>
2972- atSpan(in.offset) { makeTupleOrParens(inParens (patternsOpt())) }
3010+ atSpan(in.offset) { makeTupleOrParens(inParensWithCommas (patternsOpt())) }
29733011 case QUOTE =>
29743012 simpleExpr(Location .InPattern )
29753013 case XMLSTART =>
@@ -3015,7 +3053,7 @@ object Parsers {
30153053 * | ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
30163054 */
30173055 def argumentPatterns (): List [Tree ] =
3018- inParens (patternsOpt(Location .InPatternArgs ))
3056+ inParensWithCommas (patternsOpt(Location .InPatternArgs ))
30193057
30203058/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */
30213059
@@ -3204,7 +3242,7 @@ object Parsers {
32043242 * HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
32053243 * HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypePamClause] | ‘_’) TypeBounds
32063244 */
3207- def typeParamClause (ownerKind : ParamOwner ): List [TypeDef ] = inBrackets {
3245+ def typeParamClause (ownerKind : ParamOwner ): List [TypeDef ] = inBracketsWithCommas {
32083246
32093247 def checkVarianceOK (): Boolean =
32103248 val ok = ownerKind != ParamOwner .Def && ownerKind != ParamOwner .TypeParam
@@ -3344,7 +3382,7 @@ object Parsers {
33443382 }
33453383
33463384 // begin termParamClause
3347- inParens {
3385+ inParensWithCommas {
33483386 if in.token == RPAREN && ! prefix && ! impliedMods.is(Given ) then Nil
33493387 else
33503388 val clause =
0 commit comments