Skip to content

Commit 04da9e2

Browse files
committed
fix scala#9324: forbid no-arg java.lang.Enum unless enum
1 parent 8c56525 commit 04da9e2

File tree

6 files changed

+54
-8
lines changed

6 files changed

+54
-8
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] {
167167
ModifierNotAllowedForDefinitionID,
168168
CannotExtendJavaEnumID,
169169
InvalidReferenceInImplicitNotFoundAnnotationID,
170-
TraitMayNotDefineNativeMethodID
170+
TraitMayNotDefineNativeMethodID,
171+
JavaEnumParentArgsID
171172

172173
def errorNumber = ordinal - 2
173174
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,12 @@ import transform.SymUtils._
15281528
def explain = ""
15291529
}
15301530

1531+
class JavaEnumParentArgs(parent: Type)(using Context)
1532+
extends TypeMsg(JavaEnumParentArgsID) {
1533+
def msg = em"""not enough arguments for constructor Enum: ${hl("(name: String, ordinal: Int)")}: ${hl(parent.show)}"""
1534+
def explain = ""
1535+
}
1536+
15311537
class CannotHaveSameNameAs(sym: Symbol, cls: Symbol, reason: CannotHaveSameNameAs.Reason)(using Context)
15321538
extends SyntaxMsg(CannotHaveSameNameAsID) {
15331539
import CannotHaveSameNameAs._

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ trait Applications extends Compatibility {
897897
convertNewGenericArray(
898898
widenEnumCase(
899899
postProcessByNameArgs(funRef, app).computeNullable(),
900-
pt))
900+
pt))
901901
case _ =>
902902
handleUnexpectedFunType(tree, fun1)
903903
}

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ object RefChecks {
9595
* and required classes. Also check that only `enum` constructs extend
9696
* `java.lang.Enum`.
9797
*/
98-
private def checkParents(cls: Symbol)(using Context): Unit = cls.info match {
98+
private def checkParents(cls: Symbol, parentTrees: List[Tree])(using Context): Unit = cls.info match {
9999
case cinfo: ClassInfo =>
100100
def checkSelfConforms(other: ClassSymbol, category: String, relation: String) = {
101101
val otherSelf = other.declaredSelfTypeAsSeenFrom(cls.thisType)
@@ -109,12 +109,25 @@ object RefChecks {
109109
for (reqd <- cinfo.cls.givenSelfType.classSymbols)
110110
checkSelfConforms(reqd, "missing requirement", "required")
111111

112+
def illegalEnumFlags = !cls.isOneOf(Enum | Trait)
113+
def isJavaEnum = parents.exists(_.classSymbol == defn.JavaEnumClass)
114+
112115
// Prevent wrong `extends` of java.lang.Enum
113-
if !migrateTo3 &&
114-
!cls.isOneOf(Enum | Trait) &&
115-
parents.exists(_.classSymbol == defn.JavaEnumClass)
116-
then
116+
if !migrateTo3 && illegalEnumFlags && isJavaEnum then
117117
report.error(CannotExtendJavaEnum(cls), cls.sourcePos)
118+
else if illegalEnumFlags && isJavaEnum then
119+
val javaEnumCtor = defn.JavaEnumClass.primaryConstructor
120+
parentTrees.exists(parent =>
121+
parent.tpe.typeSymbol == defn.JavaEnumClass
122+
&& (
123+
parent match
124+
case tpd.Apply(tpd.TypeApply(fn, _), _) if fn.tpe.termSymbol eq javaEnumCtor =>
125+
// here we are simulating the error for missing arguments to a constructor.
126+
report.error(JavaEnumParentArgs(parent.tpe), cls.sourcePos)
127+
true
128+
case _ =>
129+
false
130+
))
118131

119132
case _ =>
120133
}
@@ -1089,7 +1102,7 @@ class RefChecks extends MiniPhase { thisPhase =>
10891102
override def transformTemplate(tree: Template)(using Context): Tree = try {
10901103
val cls = ctx.owner.asClass
10911104
checkOverloadedRestrictions(cls)
1092-
checkParents(cls)
1105+
checkParents(cls, tree.parents)
10931106
if (cls.is(Trait)) tree.parents.foreach(checkParentPrefix(cls, _))
10941107
checkCompanionNameClashes(cls)
10951108
checkAllOverrides(cls)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- [E160] Type Error: tests/neg/extend-java-enum-migration.scala:9:12 --------------------------------------------------
2+
9 |final class C extends jl.Enum[C] // error
3+
| ^
4+
| not enough arguments for constructor Enum: (name: String, ordinal: Int): Enum[C]
5+
-- [E160] Type Error: tests/neg/extend-java-enum-migration.scala:11:7 --------------------------------------------------
6+
11 |object O extends jl.Enum[O.type] // error
7+
| ^
8+
| not enough arguments for constructor Enum: (name: String, ordinal: Int): Enum[O.type]
9+
-- [E160] Type Error: tests/neg/extend-java-enum-migration.scala:14:6 --------------------------------------------------
10+
14 |class Sub extends T // error
11+
| ^
12+
| not enough arguments for constructor Enum: (name: String, ordinal: Int): Enum[T]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import java.{lang => jl}
2+
3+
import language.`3.0-migration`
4+
5+
// This file is different from `tests/neg/extend-java-enum.scala` as we
6+
// are testing that it is illegal to *not* pass arguments to jl.Enum
7+
// in 3.0-migration
8+
9+
final class C extends jl.Enum[C] // error
10+
11+
object O extends jl.Enum[O.type] // error
12+
13+
trait T extends jl.Enum[T] // ok
14+
class Sub extends T // error

0 commit comments

Comments
 (0)