diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index cc43e950ec10..977b82012f2f 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index f81c1bf19cb1..1d48ee5bd7df 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -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: @@ -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() diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 12a53a19931d..ecda82e14da6 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -945,7 +945,11 @@ 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", "") else if expectedErrors != actualErrors then s"""|Wrong number of errors encountered when compiling $testSource |expected: $expectedErrors, actual: $actualErrors @@ -953,8 +957,10 @@ trait ParallelTesting extends RunnerOrchestration { self => |${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 {=}: $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 {=}: $errorMap" else null } end maybeFailureMessage diff --git a/tests/neg/abstract-givens.check b/tests/neg/abstract-givens.check index 1430c5b6e950..b4cc1fede296 100644 --- a/tests/neg/abstract-givens.check +++ b/tests/neg/abstract-givens.check @@ -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 | ^ diff --git a/tests/neg/i19731.check b/tests/neg/i19731.check index eebfb924d199..fb62614f65ac 100644 --- a/tests/neg/i19731.check +++ b/tests/neg/i19731.check @@ -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 | ^ diff --git a/tests/neg/i21335.check b/tests/neg/i21335.check index a7ee092eec0e..fe62218eaa5a 100644 --- a/tests/neg/i21335.check +++ b/tests/neg/i21335.check @@ -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 diff --git a/tests/neg/i22734.check b/tests/neg/i22734.check new file mode 100644 index 000000000000..227261765da0 --- /dev/null +++ b/tests/neg/i22734.check @@ -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 |} diff --git a/tests/neg/i22734.scala b/tests/neg/i22734.scala new file mode 100644 index 000000000000..50ff2ba5a59f --- /dev/null +++ b/tests/neg/i22734.scala @@ -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 +}