Description
Diagnosis of https://github.com/scala/scala/pull/6676/files#diff-04841eeda02f00638b4cda505dbeafbeR766
Definitions.init
carefully forces core types in a specific order (e.g., first load the scala
package, then create synthetic members such as Nothing
). See this epic comment in JavaUniverse.init()
.
In reality ObjectClass.initialize
already forces the scala
package. Object
has no parent class, so the ClassfileParser
/ FromJavaClassCompleter
use definitions.AnyClass
in this case, which is defined as enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT)
.
-
Forcing the
scala
package callsopenPackageModule
, which forces the package object. -
The unpickler looks for annotations on members (
@deprecated val Stream
), which callsStreamSymbol.addAnnotation
. -
annotations
has the following "interesting" code:if (!isCompilerUniverse && !isThreadsafe(purpose = AllOps)) initialize _annotations
-
So the compiler does not initialie the
Stream
class, while runtime reflection does -
In the case of runtime reflection
- The
Stream
class is unpickled - Since
Cons
/Empty
are defined in the companion object, they are part of the pickle ofStream
- The unpickler reads the
@SVUID
annotation onEmpty
and callsaddAnnotation
- This causes
Empty extends Stream[Nothing]
to be initialized, the unpickler tries to resolvescala.Nothing
- But that fails:
Nothing
has not yet been enetered into thescala
package. Look again atDefinitions.init
, we're still inObjectClass.initialize
.Nothing
would be added only insymbolsNotPresentInBytecode
.
- The
Not sure where to break the cycle. Completing the scala
package needs the synthetic scala.Nothing
, but adding it requires the package to be completed. Suggestions welcome.