Skip to content

Commit 861f11a

Browse files
committed
Port Desugar error messages to the new scheme
1 parent abaf47e commit 861f11a

File tree

10 files changed

+116
-5
lines changed

10 files changed

+116
-5
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ object desugar {
488488
if (isEnum) {
489489
val (enumCases, enumStats) = stats.partition(DesugarEnums.isEnumCase)
490490
if (enumCases.isEmpty)
491-
ctx.error("Enumerations must contain at least one case", namePos)
491+
ctx.error(EnumerationsShouldNotBeEmpty(cdef), namePos)
492492
val enumCompanionRef = TermRefTree()
493493
val enumImport =
494494
Import(enumCompanionRef, enumCases.flatMap(caseIds).map(ImportSelector(_)))
@@ -883,12 +883,12 @@ object desugar {
883883
def flagSourcePos(flag: FlagSet) = mods.mods.find(_.flags == flag).fold(mdef.sourcePos)(_.sourcePos)
884884

885885
if (mods.is(Abstract))
886-
ctx.error(em"${hl("abstract")} modifier cannot be used for objects", flagSourcePos(Abstract))
886+
ctx.error(AbstractCannotBeUsedForObjects(mdef), flagSourcePos(Abstract))
887887
if (mods.is(Sealed))
888-
ctx.error(em"${hl("sealed")} modifier is redundant for objects", flagSourcePos(Sealed))
888+
ctx.error(ModifierRedundantForObjects(mdef, "sealed"), flagSourcePos(Sealed))
889889
// Maybe this should be an error; see https://github.com/scala/bug/issues/11094.
890890
if (mods.is(Final) && !mods.is(Synthetic))
891-
ctx.warning(em"${hl("final")} modifier is redundant for objects", flagSourcePos(Final))
891+
ctx.warning(ModifierRedundantForObjects(mdef, "final"), flagSourcePos(Final))
892892

893893
if (mods.is(Package))
894894
packageModuleDef(mdef)

compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,10 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] {
152152
MissingTypeParameterInTypeAppID,
153153
ImplicitTypesCanOnlyBeFunctionTypesID,
154154
ErasedTypesCanOnlyBeFunctionTypesID,
155-
CaseClassMissingNonImplicitParamListID
155+
CaseClassMissingNonImplicitParamListID,
156+
EnumerationsShouldNotBeEmptyID,
157+
AbstractCannotBeUsedForObjectsID,
158+
ModifierRedundantForObjectsID
156159

157160
def errorNumber = ordinal - 2
158161
}

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2408,4 +2408,46 @@ object messages {
24082408
| if you're aiming to have a case class parametrized only by implicit ones, you should
24092409
| add an explicit ${hl("()")} as a parameter list to ${cdef.name}.""".stripMargin
24102410
}
2411+
2412+
case class EnumerationsShouldNotBeEmpty(cdef: untpd.TypeDef)(implicit ctx: Context)
2413+
extends Message(EnumerationsShouldNotBeEmptyID) {
2414+
val kind: String = "Syntax"
2415+
val msg: String = "Enumerations must contain at least one case"
2416+
2417+
val explanation: String =
2418+
em"""|Enumeration ${cdef.name} must contain at least one case
2419+
|Example Usage:
2420+
| ${hl("enum")} ${cdef.name} {
2421+
| ${hl("case")} Option1, Option2
2422+
| }
2423+
|""".stripMargin
2424+
}
2425+
2426+
case class AbstractCannotBeUsedForObjects(mdef: untpd.ModuleDef)(implicit ctx: Context)
2427+
extends Message(AbstractCannotBeUsedForObjectsID) {
2428+
val kind: String = "Syntax"
2429+
val msg: String = em"${hl("abstract")} modifier cannot be used for objects"
2430+
2431+
val explanation: String =
2432+
em"""|Objects are final and cannot be extended, thus cannot have the ${hl("abstract")} modifier
2433+
|
2434+
|You may want to define an abstract class:
2435+
| ${hl("abstract")} ${hl("class")} Abstract${mdef.name} { }
2436+
|
2437+
|And extend it in an object:
2438+
| ${hl("object")} ${mdef.name} ${hl("extends")} Abstract${mdef.name} { }
2439+
|""".stripMargin
2440+
}
2441+
2442+
case class ModifierRedundantForObjects(mdef: untpd.ModuleDef, modifier: String)(implicit ctx: Context)
2443+
extends Message(ModifierRedundantForObjectsID) {
2444+
val kind: String = "Syntax"
2445+
val msg: String = em"${hl(modifier)} modifier is redundant for objects"
2446+
2447+
val explanation: String =
2448+
em"""|Objects cannot be extended making the ${hl(modifier)} modifier redundant.
2449+
|You may want to define the object without it:
2450+
| ${hl("object")} ${mdef.name} { }
2451+
|""".stripMargin
2452+
}
24112453
}

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,4 +1738,49 @@ class ErrorMessagesTests extends ErrorMessagesTest {
17381738
val CaseClassMissingNonImplicitParamList(tpe) :: Nil = messages
17391739
assertEquals("A case class must have at least one non-implicit parameter list", messages.head.msg)
17401740
}
1741+
1742+
@Test def enumMustContainOneCase =
1743+
checkMessagesAfter(RefChecks.name) {
1744+
"""
1745+
|enum Foo { }
1746+
""".stripMargin
1747+
}
1748+
.expect { (ictx, messages)
1749+
implicit val ctx: Context = ictx
1750+
assertMessageCount(1, messages)
1751+
val errorMsg = messages.head.msg
1752+
val EnumerationsShouldNotBeEmpty(typeDef) :: Nil = messages
1753+
assertEquals("Enumerations must contain at least one case", errorMsg)
1754+
assertEquals("Foo", typeDef.name.toString)
1755+
}
1756+
1757+
@Test def objectsCannotBeAbstract =
1758+
checkMessagesAfter(RefChecks.name) {
1759+
"""
1760+
|abstract object Foo { }
1761+
""".stripMargin
1762+
}
1763+
.expect { (ictx, messages)
1764+
implicit val ctx: Context = ictx
1765+
assertMessageCount(1, messages)
1766+
val errorMsg = messages.head.msg
1767+
val AbstractCannotBeUsedForObjects(mdef) :: Nil = messages
1768+
assertEquals("abstract modifier cannot be used for objects", errorMsg)
1769+
assertEquals("Foo", mdef.name.toString)
1770+
}
1771+
1772+
@Test def sealedOnObjectsIsRedundant =
1773+
checkMessagesAfter(RefChecks.name) {
1774+
"""
1775+
|sealed object Foo { }
1776+
""".stripMargin
1777+
}
1778+
.expect { (ictx, messages)
1779+
implicit val ctx: Context = ictx
1780+
assertMessageCount(1, messages)
1781+
val errorMsg = messages.head.msg
1782+
val ModifierRedundantForObjects(mdef, "sealed") :: Nil = messages
1783+
assertEquals("sealed modifier is redundant for objects", errorMsg)
1784+
assertEquals("Foo", mdef.name.toString)
1785+
}
17411786
}

tests/neg/AbstractObject.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- [E146] Syntax Error: tests/neg/AbstractObject.scala:1:0 -------------------------------------------------------------
2+
1 |abstract object A {} // error
3+
|^^^^^^^^
4+
|abstract modifier cannot be used for objects
5+
6+
longer explanation available when compiling with `-explain`

tests/neg/AbstractObject.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
abstract object A {} // error

tests/neg/EmptyEnum.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- [E145] Syntax Error: tests/neg/EmptyEnum.scala:1:5 ------------------------------------------------------------------
2+
1 |enum EmptyEnum {} // error
3+
| ^^^^^^^^^
4+
| Enumerations must contain at least one case
5+
6+
longer explanation available when compiling with `-explain`

tests/neg/EmptyEnum.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
enum EmptyEnum {} // error

tests/neg/SealedObject.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- [E147] Syntax Error: tests/neg/SealedObject.scala:1:0 ---------------------------------------------------------------
2+
1 |sealed object A {} // error
3+
|^^^^^^
4+
|sealed modifier is redundant for objects
5+
6+
longer explanation available when compiling with `-explain`

tests/neg/SealedObject.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
sealed object A {} // error

0 commit comments

Comments
 (0)