Skip to content

Adjust error on bad enum #23080

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,9 @@ trait Checking {
report.error(ClassCannotExtendEnum(cls, firstParent), cdef.srcPos)
if cls.isEnumClass && !isJavaEnum then
checkExistingOrdinal
if cls.isEnum && cls.is(Abstract) then
if cls.children.exists(!_.isClass) && cls.info.decls.exists(m => m.is(Deferred) && m.isTerm) then
report.error(em"enum $cls has an abstract member and an unparameterized case", cdef.srcPos)
}

/** Check that the firstParent for an enum case derives from the declaring enum class, if not, adds it as a parent
Expand Down
19 changes: 16 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,9 @@ object RefChecks {
def showDclAndLocation(sym: Symbol) =
s"${sym.showDcl} in ${sym.owner.showLocated}"
def undefined(msg: String) =
abstractClassError(false, s"${showDclAndLocation(member)} is not defined $msg")
val notdefined = s"${showDclAndLocation(member)} is not defined"
val text = if !msg.isEmpty then s"$notdefined $msg" else notdefined
abstractClassError(mustBeMixin = false, text)
val underlying = member.underlyingSymbol

// Give a specific error message for abstract vars based on why it fails:
Expand Down Expand Up @@ -956,8 +958,19 @@ object RefChecks {
if (abstractErrors.isEmpty)
checkNoAbstractDecls(clazz)

if (abstractErrors.nonEmpty)
report.error(abstractErrorMessage, clazz.srcPos)
def errorPos(cls: ClassSymbol) =
val isEnumAnonCls = // courtesy of Checking.checkEnum
cls.isAnonymousClass
&& cls.owner.isTerm
&& (cls.owner.flagsUNSAFE.isAllOf(EnumCase)
|| ((cls.owner.name eq nme.DOLLAR_NEW) && cls.owner.flagsUNSAFE.isAllOf(Private | Synthetic)))
if isEnumAnonCls then
cls.parentSyms.head.children.filterNot(_.isClass).head.srcPos
else
cls.srcPos

if abstractErrors.nonEmpty then
report.error(abstractErrorMessage, errorPos(clazz))

checkMemberTypesOK()
checkCaseClassInheritanceInvariant()
Expand Down
12 changes: 9 additions & 3 deletions compiler/test/dotty/tools/vulpix/ParallelTesting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -945,16 +945,22 @@ trait ParallelTesting extends RunnerOrchestration { self =>

Option {
if actualErrors == 0 then s"\nNo errors found when compiling neg test $testSource"
else if expectedErrors == 0 then s"\nNo errors expected/defined in $testSource -- use // error or // nopos-error"
else if expectedErrors == 0 then
s"""|
|No errors expected/defined in $testSource -- use // error or // nopos-error"
|$showErrors
|""".stripMargin.trim.linesIterator.mkString("\n", "\n", "")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the most important part of this PR.

else if expectedErrors != actualErrors then
s"""|Wrong number of errors encountered when compiling $testSource
|expected: $expectedErrors, actual: $actualErrors
|${expected.mkString("Unfulfilled expectations:\n", "\n", "")}
|${unexpected.mkString("Unexpected errors:\n", "\n", "")}
|$showErrors
|""".stripMargin.trim.linesIterator.mkString("\n", "\n", "")
else if hasMissingAnnotations then s"\nErrors found on incorrect row numbers when compiling $testSource\n$showErrors"
else if !errorMap.isEmpty then s"\nExpected error(s) have {<error position>=<unreported error>}: $errorMap"
else if hasMissingAnnotations then
s"\nErrors found on incorrect row numbers when compiling $testSource\n$showErrors"
else if !errorMap.isEmpty then
s"\nExpected error(s) have {<error position>=<unreported error>}: $errorMap"
else null
}
end maybeFailureMessage
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/abstract-givens.check
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- Error: tests/neg/abstract-givens.scala:11:8 -------------------------------------------------------------------------
11 | given s: [T] => T => Seq[T]: // error
| ^
|instance cannot be created, since def iterator: Iterator[A] in trait IterableOnce in package scala.collection is not defined
|instance cannot be created, since def iterator: Iterator[A] in trait IterableOnce in package scala.collection is not defined
-- [E164] Declaration Error: tests/neg/abstract-givens.scala:8:8 -------------------------------------------------------
8 | given y(using Int): String = summon[Int].toString * 22 // error
| ^
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i19731.check
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- Error: tests/neg/i19731.scala:4:6 -----------------------------------------------------------------------------------
4 |class F1 extends Foo: // error
| ^
| class F1 needs to be abstract, since def foo(): Unit in class F1 is not defined
| class F1 needs to be abstract, since def foo(): Unit in class F1 is not defined
-- Error: tests/neg/i19731.scala:7:6 -----------------------------------------------------------------------------------
7 |class F2 extends Foo: // error
| ^
Expand Down
4 changes: 2 additions & 2 deletions tests/neg/i21335.check
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
-- Error: tests/neg/i21335.scala:7:6 -----------------------------------------------------------------------------------
7 |class Z1 extends Bar1 // error
| ^
| class Z1 needs to be abstract, since override def bar(): Bar1 in trait Bar1 is not defined
| class Z1 needs to be abstract, since override def bar(): Bar1 in trait Bar1 is not defined
-- Error: tests/neg/i21335.scala:12:6 ----------------------------------------------------------------------------------
12 |class Z2 extends Bar2 // error
| ^
| class Z2 needs to be abstract, since def bar(): Bar2 in trait Bar2 is not defined
| class Z2 needs to be abstract, since def bar(): Bar2 in trait Bar2 is not defined
9 changes: 9 additions & 0 deletions tests/neg/i22734.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- Error: tests/neg/i22734.scala:5:5 -----------------------------------------------------------------------------------
5 |enum Foo { // error
|^
|enum class Foo has an abstract member and an unparameterized case
6 | case Empty // refchecks error
7 | case NonEmpty(item: String)
8 | case Decoy // hopefully not here
9 | def item: String
10 |}
11 changes: 11 additions & 0 deletions tests/neg/i22734.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
trait T:
def item: String
object X extends T // refchecks error status quo

enum Foo { // error
case Empty // refchecks error
case NonEmpty(item: String)
case Decoy // hopefully not here

def item: String
}
Loading