Skip to content

Commit 747f927

Browse files
committed
Hijack java.lang.Enum constructor in Definitions
1 parent 8144f98 commit 747f927

File tree

2 files changed

+39
-12
lines changed

2 files changed

+39
-12
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,16 @@ class Definitions {
192192
cls
193193
}
194194

195+
private def completeTransformedJavaClass(cls: ClassSymbol, ensureCtor: Boolean = true): ClassSymbol = {
196+
// The companion object of a Java class doesn't really exist, `NoType` is the general
197+
// technique to do that. Here we need to set it before completing
198+
// attempt to load Object's classfile, which causes issue #1648.
199+
val companion = JavaLangPackageVal.info.decl(cls.name.toTermName).symbol
200+
companion.moduleClass.info = NoType // to indicate that it does not really exist
201+
companion.info = NoType // to indicate that it does not really exist
202+
completeClass(cls, ensureCtor)
203+
}
204+
195205
lazy val RootClass: ClassSymbol = ctx.newPackageSymbol(
196206
NoSymbol, nme.ROOT, (root, rootcls) => ctx.base.rootLoader(root)).moduleClass.asClass
197207
lazy val RootPackage: TermSymbol = ctx.newSymbol(
@@ -292,15 +302,7 @@ class Definitions {
292302
assert(!cls.isCompleted, "race for completing java.lang.Object")
293303
cls.info = ClassInfo(cls.owner.thisType, cls, AnyClass.typeRef :: Nil, newScope)
294304
cls.setFlag(NoInits)
295-
296-
// The companion object doesn't really exist, `NoType` is the general
297-
// technique to do that. Here we need to set it before completing
298-
// attempt to load Object's classfile, which causes issue #1648.
299-
val companion = JavaLangPackageVal.info.decl(nme.Object).symbol
300-
companion.moduleClass.info = NoType // to indicate that it does not really exist
301-
companion.info = NoType // to indicate that it does not really exist
302-
303-
completeClass(cls)
305+
completeTransformedJavaClass(cls)
304306
}
305307
def ObjectType: TypeRef = ObjectClass.typeRef
306308

@@ -614,6 +616,26 @@ class Definitions {
614616
JavaSerializableClass.typeRef
615617
else
616618
ctx.requiredClassRef("scala.Serializable")
619+
620+
lazy val JavaEnumClass: ClassSymbol = {
621+
val cls = ctx.requiredClass("java.lang.Enum")
622+
val constr = cls.primaryConstructor
623+
val newInfo = constr.info match {
624+
case info: PolyType =>
625+
info.resType match {
626+
case meth: MethodType =>
627+
info.derivedLambdaType(
628+
resType = meth.derivedLambdaType(
629+
paramNames = Nil, paramInfos = Nil))
630+
}
631+
}
632+
constr.info = newInfo
633+
constr.termRef.recomputeDenot()
634+
cls.setFlag(NoInits)
635+
completeTransformedJavaClass(cls, ensureCtor = false)
636+
}
637+
def JavaEnumType = JavaEnumClass.typeRef
638+
617639
def SerializableClass(implicit ctx: Context): ClassSymbol = SerializableType.symbol.asClass
618640
lazy val StringBuilderType: TypeRef = ctx.requiredClassRef("scala.collection.mutable.StringBuilder")
619641
def StringBuilderClass(implicit ctx: Context): ClassSymbol = StringBuilderType.symbol.asClass
@@ -1438,7 +1460,7 @@ class Definitions {
14381460
ScalaPackageClass.enter(m)
14391461

14401462
// force initialization of every symbol that is synthesized or hijacked by the compiler
1441-
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses()
1463+
val forced = syntheticCoreClasses ++ syntheticCoreMethods ++ ScalaValueClasses() :+ JavaEnumClass
14421464

14431465
isInitialized = true
14441466
}

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,8 +814,13 @@ object Denotations {
814814
def invalidateInheritedInfo(): Unit = ()
815815

816816
private def updateValidity()(implicit ctx: Context): this.type = {
817-
assert(ctx.runId >= validFor.runId || ctx.settings.YtestPickler.value, // mixing test pickler with debug printing can travel back in time
818-
s"denotation $this invalid in run ${ctx.runId}. ValidFor: $validFor")
817+
assert(
818+
ctx.runId >= validFor.runId ||
819+
ctx.settings.YtestPickler.value || // mixing test pickler with debug printing can travel back in time
820+
symbol.isContainedIn(defn.JavaEnumClass) || // the java.lang.Enum constructor highjacking leads to backwards time travel...
821+
symbol.is(Package), // ... which also means packages can travel backwards in time.
822+
823+
s"denotation $this invalid in run ${ctx.runId}. ValidFor: $validFor")
819824
var d: SingleDenotation = this
820825
do {
821826
d.validFor = Period(ctx.period.runId, d.validFor.firstPhaseId, d.validFor.lastPhaseId)

0 commit comments

Comments
 (0)