Skip to content

Commit

Permalink
Mention , in addition to ) in error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
odersky committed Oct 29, 2023
1 parent ffb2ab7 commit 45fc82a
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 23 deletions.
56 changes: 38 additions & 18 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -555,10 +555,29 @@ object Parsers {
accept(tok)
try body finally accept(tok + 1)

/** Same as enclosed, but if closing token is missing, add `,` to the expected tokens
* in the error message provided the next token could have followed a `,`.
*/
def enclosedWithCommas[T](tok: Token, body: => T): T =
accept(tok)
val closing = tok + 1
val isEmpty = in.token == closing
val ts = body
if in.token != closing then
val followComma =
if tok == LPAREN then canStartExprTokens3 else canStartTypeTokens
val prefix = if !isEmpty && followComma.contains(in.token) then "',' or " else ""
syntaxErrorOrIncomplete(ExpectedTokenButFound(closing, in.token, prefix))
if in.token == closing then in.nextToken()
ts

def inParens[T](body: => T): T = enclosed(LPAREN, body)
def inBraces[T](body: => T): T = enclosed(LBRACE, body)
def inBrackets[T](body: => T): T = enclosed(LBRACKET, body)

def inParensWithCommas[T](body: => T): T = enclosedWithCommas(LPAREN, body)
def inBracketsWithCommas[T](body: => T): T = enclosedWithCommas(LBRACKET, body)

def inBracesOrIndented[T](body: => T, rewriteWithColon: Boolean = false): T =
if in.token == INDENT then
val rewriteToBraces = in.rewriteNoIndent
Expand Down Expand Up @@ -1672,7 +1691,7 @@ object Parsers {
/** FunParamClause ::= ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
*/
def funParamClause(): List[ValDef] =
inParens(commaSeparated(() => typedFunParam(in.offset, ident())))
inParensWithCommas(commaSeparated(() => typedFunParam(in.offset, ident())))

def funParamClauses(): List[List[ValDef]] =
if in.token == LPAREN then funParamClause() :: funParamClauses() else Nil
Expand Down Expand Up @@ -1853,7 +1872,7 @@ object Parsers {
else
def singletonArgs(t: Tree): Tree =
if in.token == LPAREN && in.featureEnabled(Feature.dependent)
then singletonArgs(AppliedTypeTree(t, inParens(commaSeparated(singleton))))
then singletonArgs(AppliedTypeTree(t, inParensWithCommas(commaSeparated(singleton))))
else t
singletonArgs(simpleType1())

Expand All @@ -1869,7 +1888,7 @@ object Parsers {
def simpleType1() = simpleTypeRest {
if in.token == LPAREN then
atSpan(in.offset) {
makeTupleOrParens(inParens(argTypes(namedOK = false, wildOK = true)))
makeTupleOrParens(inParensWithCommas(argTypes(namedOK = false, wildOK = true)))
}
else if in.token == LBRACE then
atSpan(in.offset) { RefinedTypeTree(EmptyTree, refinement(indentOK = false)) }
Expand Down Expand Up @@ -2022,7 +2041,8 @@ object Parsers {
/** TypeArgs ::= `[' Type {`,' Type} `]'
* NamedTypeArgs ::= `[' NamedTypeArg {`,' NamedTypeArg} `]'
*/
def typeArgs(namedOK: Boolean, wildOK: Boolean): List[Tree] = inBrackets(argTypes(namedOK, wildOK))
def typeArgs(namedOK: Boolean, wildOK: Boolean): List[Tree] =
inBracketsWithCommas(argTypes(namedOK, wildOK))

/** Refinement ::= `{' RefineStatSeq `}'
*/
Expand Down Expand Up @@ -2518,7 +2538,7 @@ object Parsers {
placeholderParams = param :: placeholderParams
atSpan(start) { Ident(pname) }
case LPAREN =>
atSpan(in.offset) { makeTupleOrParens(inParens(exprsInParensOrBindings())) }
atSpan(in.offset) { makeTupleOrParens(inParensWithCommas(exprsInParensOrBindings())) }
case LBRACE | INDENT =>
canApply = false
blockExpr()
Expand Down Expand Up @@ -2616,15 +2636,15 @@ object Parsers {
/** ParArgumentExprs ::= `(' [‘using’] [ExprsInParens] `)'
* | `(' [ExprsInParens `,'] PostfixExpr `*' ')'
*/
def parArgumentExprs(): (List[Tree], Boolean) = inParens {
if in.token == RPAREN then
(Nil, false)
else if isIdent(nme.using) then
in.nextToken()
(commaSeparated(argumentExpr), true)
else
(commaSeparated(argumentExpr), false)
}
def parArgumentExprs(): (List[Tree], Boolean) =
inParensWithCommas:
if in.token == RPAREN then
(Nil, false)
else if isIdent(nme.using) then
in.nextToken()
(commaSeparated(argumentExpr), true)
else
(commaSeparated(argumentExpr), false)

/** ArgumentExprs ::= ParArgumentExprs
* | [nl] BlockExpr
Expand Down Expand Up @@ -2985,7 +3005,7 @@ object Parsers {
case USCORE =>
wildcardIdent()
case LPAREN =>
atSpan(in.offset) { makeTupleOrParens(inParens(patternsOpt())) }
atSpan(in.offset) { makeTupleOrParens(inParensWithCommas(patternsOpt())) }
case QUOTE =>
simpleExpr(Location.InPattern)
case XMLSTART =>
Expand Down Expand Up @@ -3031,7 +3051,7 @@ object Parsers {
* | ‘(’ [Patterns ‘,’] PatVar ‘*’ ‘)’
*/
def argumentPatterns(): List[Tree] =
inParens(patternsOpt(Location.InPatternArgs))
inParensWithCommas(patternsOpt(Location.InPatternArgs))

/* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */

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

def checkVarianceOK(): Boolean =
val ok = ownerKind != ParamOwner.Def && ownerKind != ParamOwner.TypeParam
Expand Down Expand Up @@ -3360,7 +3380,7 @@ object Parsers {
}

// begin termParamClause
inParens {
inParensWithCommas {
if in.token == RPAREN && !prefix && !impliedMods.is(Given) then Nil
else
val clause =
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1187,7 +1187,7 @@ extends ReferenceMsg(ForwardReferenceExtendsOverDefinitionID) {
|"""
}

class ExpectedTokenButFound(expected: Token, found: Token)(using Context)
class ExpectedTokenButFound(expected: Token, found: Token, prefix: String = "")(using Context)
extends SyntaxMsg(ExpectedTokenButFoundID) {

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

def explain(using Context) =
if (Tokens.isIdentifier(expected) && Tokens.isKeyword(found))
Expand Down
28 changes: 28 additions & 0 deletions tests/neg/i18734.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-- [E040] Syntax Error: tests/neg/i18734.scala:7:8 ---------------------------------------------------------------------
7 | Foo(1 2) // error
| ^
| ',' or ')' expected, but integer literal found
-- [E040] Syntax Error: tests/neg/i18734.scala:9:8 ---------------------------------------------------------------------
9 | Foo(x y) // error
| ^
| ',' or ')' expected, but identifier found
-- [E040] Syntax Error: tests/neg/i18734.scala:11:8 --------------------------------------------------------------------
11 | Foo(1 b = 2) // error
| ^
| ',' or ')' expected, but identifier found
-- [E040] Syntax Error: tests/neg/i18734.scala:16:4 --------------------------------------------------------------------
16 | b = 2 // error
| ^
| ',' or ')' expected, but identifier found
-- [E040] Syntax Error: tests/neg/i18734.scala:19:32 -------------------------------------------------------------------
19 | val f: (Int, Int) => Int = (x y) => x + y // error
| ^
| ',' or ')' expected, but identifier found
-- [E040] Syntax Error: tests/neg/i18734.scala:23:10 -------------------------------------------------------------------
23 | bar[Int String](1 2) // error // error
| ^^^^^^
| ',' or ']' expected, but identifier found
-- [E040] Syntax Error: tests/neg/i18734.scala:23:20 -------------------------------------------------------------------
23 | bar[Int String](1 2) // error // error
| ^
| ',' or ')' expected, but integer literal found
25 changes: 25 additions & 0 deletions tests/neg/i18734.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
case class Foo(a: Int, b: Int)

object Bar:
val x = 1
val y = 2

Foo(1 2) // error

Foo(x y) // error

Foo(1 b = 2) // error

// Or
Foo(
a = 1
b = 2 // error
)

val f: (Int, Int) => Int = (x y) => x + y // error

def bar[X, Y](x: X, y: Y) = ???

bar[Int String](1 2) // error // error


2 changes: 1 addition & 1 deletion tests/neg/i5498-postfixOps.check
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
-- [E040] Syntax Error: tests/neg/i5498-postfixOps.scala:6:29 ----------------------------------------------------------
6 | Seq(1, 2).filter(List(1,2) contains) // error: usage of postfix operator // error // error (type error) // error (type error)
| ^^^^^^^^
| ')' expected, but identifier found
| ',' or ')' expected, but identifier found
-- [E172] Type Error: tests/neg/i5498-postfixOps.scala:6:0 -------------------------------------------------------------
6 | Seq(1, 2).filter(List(1,2) contains) // error: usage of postfix operator // error // error (type error) // error (type error)
|^
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/syntax-error-recovery.check
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:19:4 -----------------------------------------------------
19 | if x == 0 then println(bar) // error
| ^^
| ')' expected, but 'if' found
| ',' or ')' expected, but 'if' found
-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:23:12 ----------------------------------------------------
23 | if x < 0) then // error
| ^
Expand All @@ -25,7 +25,7 @@
-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:48:4 -----------------------------------------------------
48 | if x == 0 then println(bar) // error
| ^^
| ')' expected, but 'if' found
| ',' or ')' expected, but 'if' found
-- [E040] Syntax Error: tests/neg/syntax-error-recovery.scala:52:12 ----------------------------------------------------
52 | if x < 0) then // error
| ^
Expand Down

0 comments on commit 45fc82a

Please sign in to comment.