Skip to content

Fragile initialization of runtime reflection universe, forces a large graph #10903

Open
@lrytz

Description

@lrytz

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 calls openPackageModule, which forces the package object.

  • The unpickler looks for annotations on members (@deprecated val Stream), which calls StreamSymbol.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 of Stream
    • The unpickler reads the @SVUID annotation on Empty and calls addAnnotation
    • This causes Empty extends Stream[Nothing] to be initialized, the unpickler tries to resolve scala.Nothing
    • But that fails: Nothing has not yet been enetered into the scala package. Look again at Definitions.init, we're still in ObjectClass.initialize. Nothing would be added only in symbolsNotPresentInBytecode.

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions