Skip to content

Commit 45fc82a

Browse files
committed
Mention , in addition to ) in error messages
1 parent ffb2ab7 commit 45fc82a

File tree

6 files changed

+96
-23
lines changed

6 files changed

+96
-23
lines changed

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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
@@ -1672,7 +1691,7 @@ object Parsers {
16721691
/** FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
16731692
*/
16741693
def funParamClause(): List[ValDef] =
1675-
inParens(commaSeparated(() => typedFunParam(in.offset, ident())))
1694+
inParensWithCommas(commaSeparated(() => typedFunParam(in.offset, ident())))
16761695

16771696
def funParamClauses(): List[List[ValDef]] =
16781697
if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
@@ -1853,7 +1872,7 @@ object Parsers {
18531872
else
18541873
def singletonArgs(t: Tree): Tree =
18551874
if in.token == LPAREN && in.featureEnabled(Feature.dependent)
1856-
then singletonArgs(AppliedTypeTree(t, inParens(commaSeparated(singleton))))
1875+
then singletonArgs(AppliedTypeTree(t, inParensWithCommas(commaSeparated(singleton))))
18571876
else t
18581877
singletonArgs(simpleType1())
18591878

@@ -1869,7 +1888,7 @@ object Parsers {
18691888
def simpleType1() = simpleTypeRest {
18701889
if in.token == LPAREN then
18711890
atSpan(in.offset) {
1872-
makeTupleOrParens(inParens(argTypes(namedOK = false, wildOK = true)))
1891+
makeTupleOrParens(inParensWithCommas(argTypes(namedOK = false, wildOK = true)))
18731892
}
18741893
else if in.token == LBRACE then
18751894
atSpan(in.offset) { RefinedTypeTree(EmptyTree, refinement(indentOK = false)) }
@@ -2022,7 +2041,8 @@ object Parsers {
20222041
/** TypeArgs ::= `[' Type {`,' Type} `]'
20232042
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
20242043
*/
2025-
def typeArgs(namedOK: Boolean, wildOK: Boolean): List[Tree] = inBrackets(argTypes(namedOK, wildOK))
2044+
def typeArgs(namedOK: Boolean, wildOK: Boolean): List[Tree] =
2045+
inBracketsWithCommas(argTypes(namedOK, wildOK))
20262046

20272047
/** Refinement ::= `{' RefineStatSeq `}'
20282048
*/
@@ -2518,7 +2538,7 @@ object Parsers {
25182538
placeholderParams = param :: placeholderParams
25192539
atSpan(start) { Ident(pname) }
25202540
case LPAREN =>
2521-
atSpan(in.offset) { makeTupleOrParens(inParens(exprsInParensOrBindings())) }
2541+
atSpan(in.offset) { makeTupleOrParens(inParensWithCommas(exprsInParensOrBindings())) }
25222542
case LBRACE | INDENT =>
25232543
canApply = false
25242544
blockExpr()
@@ -2616,15 +2636,15 @@ object Parsers {
26162636
/** ParArgumentExprs ::= `(' [‘using’] [ExprsInParens] `)'
26172637
* | `(' [ExprsInParens `,'] PostfixExpr `*' ')'
26182638
*/
2619-
def parArgumentExprs(): (List[Tree], Boolean) = inParens {
2620-
if in.token == RPAREN then
2621-
(Nil, false)
2622-
else if isIdent(nme.using) then
2623-
in.nextToken()
2624-
(commaSeparated(argumentExpr), true)
2625-
else
2626-
(commaSeparated(argumentExpr), false)
2627-
}
2639+
def parArgumentExprs(): (List[Tree], Boolean) =
2640+
inParensWithCommas:
2641+
if in.token == RPAREN then
2642+
(Nil, false)
2643+
else if isIdent(nme.using) then
2644+
in.nextToken()
2645+
(commaSeparated(argumentExpr), true)
2646+
else
2647+
(commaSeparated(argumentExpr), false)
26282648

26292649
/** ArgumentExprs ::= ParArgumentExprs
26302650
* | [nl] BlockExpr
@@ -2985,7 +3005,7 @@ object Parsers {
29853005
case USCORE =>
29863006
wildcardIdent()
29873007
case LPAREN =>
2988-
atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt())) }
3008+
atSpan(in.offset) { makeTupleOrParens(inParensWithCommas(patternsOpt())) }
29893009
case QUOTE =>
29903010
simpleExpr(Location.InPattern)
29913011
case XMLSTART =>
@@ -3031,7 +3051,7 @@ object Parsers {
30313051
* | ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
30323052
*/
30333053
def argumentPatterns(): List[Tree] =
3034-
inParens(patternsOpt(Location.InPatternArgs))
3054+
inParensWithCommas(patternsOpt(Location.InPatternArgs))
30353055

30363056
/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */
30373057

@@ -3220,7 +3240,7 @@ object Parsers {
32203240
* HkTypeParamClause ::= ‘[’ HkTypeParam {‘,’ HkTypeParam} ‘]’
32213241
* HkTypeParam ::= {Annotation} [‘+’ | ‘-’] (id [HkTypePamClause] | ‘_’) TypeBounds
32223242
*/
3223-
def typeParamClause(ownerKind: ParamOwner): List[TypeDef] = inBrackets {
3243+
def typeParamClause(ownerKind: ParamOwner): List[TypeDef] = inBracketsWithCommas {
32243244

32253245
def checkVarianceOK(): Boolean =
32263246
val ok = ownerKind != ParamOwner.Def && ownerKind != ParamOwner.TypeParam
@@ -3360,7 +3380,7 @@ object Parsers {
33603380
}
33613381

33623382
// begin termParamClause
3363-
inParens {
3383+
inParensWithCommas {
33643384
if in.token == RPAREN && !prefix && !impliedMods.is(Given) then Nil
33653385
else
33663386
val clause =

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,7 @@ extends ReferenceMsg(ForwardReferenceExtendsOverDefinitionID) {
11871187
|"""
11881188
}
11891189

1190-
class ExpectedTokenButFound(expected: Token, found: Token)(using Context)
1190+
class ExpectedTokenButFound(expected: Token, found: Token, prefix: String = "")(using Context)
11911191
extends SyntaxMsg(ExpectedTokenButFoundID) {
11921192

11931193
private def foundText = Tokens.showToken(found)
@@ -1196,7 +1196,7 @@ extends SyntaxMsg(ExpectedTokenButFoundID) {
11961196
val expectedText =
11971197
if (Tokens.isIdentifier(expected)) "an identifier"
11981198
else Tokens.showToken(expected)
1199-
i"""${expectedText} expected, but ${foundText} found"""
1199+
i"""$prefix$expectedText expected, but $foundText found"""
12001200

12011201
def explain(using Context) =
12021202
if (Tokens.isIdentifier(expected) && Tokens.isKeyword(found))

tests/neg/i18734.check

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-- [E040] Syntax Error: tests/neg/i18734.scala:7:8 ---------------------------------------------------------------------
2+
7 | Foo(1 2) // error
3+
| ^
4+
| ',' or ')' expected, but integer literal found
5+
-- [E040] Syntax Error: tests/neg/i18734.scala:9:8 ---------------------------------------------------------------------
6+
9 | Foo(x y) // error
7+
| ^
8+
| ',' or ')' expected, but identifier found
9+
-- [E040] Syntax Error: tests/neg/i18734.scala:11:8 --------------------------------------------------------------------
10+
11 | Foo(1 b = 2) // error
11+
| ^
12+
| ',' or ')' expected, but identifier found
13+
-- [E040] Syntax Error: tests/neg/i18734.scala:16:4 --------------------------------------------------------------------
14+
16 | b = 2 // error
15+
| ^
16+
| ',' or ')' expected, but identifier found
17+
-- [E040] Syntax Error: tests/neg/i18734.scala:19:32 -------------------------------------------------------------------
18+
19 | val f: (Int, Int) => Int = (x y) => x + y // error
19+
| ^
20+
| ',' or ')' expected, but identifier found
21+
-- [E040] Syntax Error: tests/neg/i18734.scala:23:10 -------------------------------------------------------------------
22+
23 | bar[Int String](1 2) // error // error
23+
| ^^^^^^
24+
| ',' or ']' expected, but identifier found
25+
-- [E040] Syntax Error: tests/neg/i18734.scala:23:20 -------------------------------------------------------------------
26+
23 | bar[Int String](1 2) // error // error
27+
| ^
28+
| ',' or ')' expected, but integer literal found

tests/neg/i18734.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
case class Foo(a: Int, b: Int)
2+
3+
object Bar:
4+
val x = 1
5+
val y = 2
6+
7+
Foo(1 2) // error
8+
9+
Foo(x y) // error
10+
11+
Foo(1 b = 2) // error
12+
13+
// Or
14+
Foo(
15+
a = 1
16+
b = 2 // error
17+
)
18+
19+
val f: (Int, Int) => Int = (x y) => x + y // error
20+
21+
def bar[X, Y](x: X, y: Y) = ???
22+
23+
bar[Int String](1 2) // error // error
24+
25+

tests/neg/i5498-postfixOps.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
-- [E040] Syntax Error: tests/neg/i5498-postfixOps.scala:6:29 ----------------------------------------------------------
88
6 | Seq(1, 2).filter(List(1,2) contains) // error: usage of postfix operator // error // error (type error) // error (type error)
99
| ^^^^^^^^
10-
| ')' expected, but identifier found
10+
| ',' or ')' expected, but identifier found
1111
-- [E172] Type Error: tests/neg/i5498-postfixOps.scala:6:0 -------------------------------------------------------------
1212
6 | Seq(1, 2).filter(List(1,2) contains) // error: usage of postfix operator // error // error (type error) // error (type error)
1313
|^

tests/neg/syntax-error-recovery.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:19:4 -----------------------------------------------------
1010
19 | if x == 0 then println(bar) // error
1111
| ^^
12-
| ')' expected, but 'if' found
12+
| ',' or ')' expected, but 'if' found
1313
-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:23:12 ----------------------------------------------------
1414
23 | if x < 0) then // error
1515
| ^
@@ -25,7 +25,7 @@
2525
-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:48:4 -----------------------------------------------------
2626
48 | if x == 0 then println(bar) // error
2727
| ^^
28-
| ')' expected, but 'if' found
28+
| ',' or ')' expected, but 'if' found
2929
-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:52:12 ----------------------------------------------------
3030
52 | if x < 0) then // error
3131
| ^

0 commit comments

Comments
 (0)