Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add compilation unit info to ClassSymbol #19010

Merged
31 changes: 31 additions & 0 deletions compiler/src/dotty/tools/dotc/core/CompilationUnitInfo.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dotty.tools.dotc.core

import dotty.tools.io.AbstractFile
import dotty.tools.tasty.TastyVersion

/** Information about the compilation unit of a class symbol.
*
* @param associatedFile The source or class file from which this class or
* the class containing this symbol was generated,
* null if not applicable.
* @param tastyVersion The TASTy version (major, minor, experimental)
* @param explicitNulls This compilation unit has explicit nulls enabled?
*/
class CompilationUnitInfo(
val associatedFile: AbstractFile,
val tastyVersion: Option[TastyVersion],
val explicitNulls: Boolean
) {

override def toString(): String =
s"CompilationUnitInfo($associatedFile, $tastyVersion)"
}

object CompilationUnitInfo:
def apply(assocFile: AbstractFile | Null, explicitNulls: Boolean = false): CompilationUnitInfo | Null =
if assocFile == null then null
else new CompilationUnitInfo(
assocFile,
tastyVersion = None,
explicitNulls = explicitNulls,
)
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1409,7 +1409,7 @@ class Definitions {
),
privateWithin = patch.privateWithin,
coord = denot.symbol.coord,
assocFile = denot.symbol.associatedFile
compUnitInfo = denot.symbol.compilationUnitInfo
)

def makeNonClassSymbol(patch: Symbol) =
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -298,14 +298,13 @@ object Denotations {
name: Name,
site: Denotation = NoDenotation,
args: List[Type] = Nil,
source: AbstractFile | Null = null,
bishabosha marked this conversation as resolved.
Show resolved Hide resolved
generateStubs: Boolean = true)
(p: Symbol => Boolean)
(using Context): Symbol =
disambiguate(p) match {
case m @ MissingRef(ownerd, name) if generateStubs =>
if ctx.settings.YdebugMissingRefs.value then m.ex.printStackTrace()
newStubSymbol(ownerd.symbol, name, source)
newStubSymbol(ownerd.symbol, name)
case NoDenotation | _: NoQualifyingRef | _: MissingRef =>
def argStr = if (args.isEmpty) "" else i" matching ($args%, %)"
val msg =
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/NamerOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ object NamerOps:
ConstructorCompanionFlags, ConstructorCompanionFlags,
constructorCompanionCompleter(cls),
coord = cls.coord,
assocFile = cls.assocFile)
compUnitInfo = cls.compUnitInfo)
companion.moduleClass.registerCompanion(cls)
cls.registerCompanion(companion.moduleClass)
companion
Expand All @@ -150,7 +150,7 @@ object NamerOps:
newSymbol(tsym.owner, tsym.name.toTermName,
ConstructorCompanionFlags | StableRealizable | Method, ExprType(prefix.select(proxy)), coord = tsym.coord)

/** Add all necesssary constructor proxy symbols for members of class `cls`. This means:
/** Add all necessary constructor proxy symbols for members of class `cls`. This means:
*
* - if a member is a class, or type alias, that needs a constructor companion, add one,
* provided no member with the same name exists.
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2588,7 +2588,7 @@ object SymDenotations {
for (sym <- scope.toList.iterator)
// We need to be careful to not force the denotation of `sym` here,
// otherwise it will be brought forward to the current run.
if (sym.defRunId != ctx.runId && sym.isClass && sym.asClass.assocFile == file)
if (sym.defRunId != ctx.runId && sym.isClass && sym.asClass.compUnitInfo != null && sym.asClass.compUnitInfo.nn.associatedFile == file)
scope.unlink(sym, sym.lastKnownDenotation.name)
}
}
Expand Down
59 changes: 38 additions & 21 deletions compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ import ast.desugar

import parsing.JavaParsers.OutlineJavaParser
import parsing.Parsers.OutlineParser
import dotty.tools.tasty.{TastyHeaderUnpickler, UnpickleException, UnpicklerConfig}
import dotty.tools.tasty.{TastyHeaderUnpickler, UnpickleException, UnpicklerConfig, TastyVersion}
import dotty.tools.dotc.core.tasty.TastyUnpickler


object SymbolLoaders {
import ast.untpd.*

Expand All @@ -52,7 +51,7 @@ object SymbolLoaders {
def enterClass(
owner: Symbol, name: PreName, completer: SymbolLoader,
flags: FlagSet = EmptyFlags, scope: Scope = EmptyScope)(using Context): Symbol = {
val cls = newClassSymbol(owner, name.toTypeName.unmangleClassName.decode, flags, completer, assocFile = completer.sourceFileOrNull)
val cls = newClassSymbol(owner, name.toTypeName.unmangleClassName.decode, flags, completer, compUnitInfo = completer.compilationUnitInfo)
enterNew(owner, cls, completer, scope)
}

Expand All @@ -64,7 +63,7 @@ object SymbolLoaders {
val module = newModuleSymbol(
owner, name.toTermName.decode, modFlags, clsFlags,
(module, _) => completer.proxy.withDecls(newScope).withSourceModule(module),
assocFile = completer.sourceFileOrNull)
compUnitInfo = completer.compilationUnitInfo)
enterNew(owner, module, completer, scope)
enterNew(owner, module.moduleClass, completer, scope)
}
Expand Down Expand Up @@ -213,7 +212,7 @@ object SymbolLoaders {
/** Load contents of a package
*/
class PackageLoader(_sourceModule: TermSymbol, classPath: ClassPath) extends SymbolLoader {
override def sourceFileOrNull: AbstractFile | Null = null
def compilationUnitInfo: CompilationUnitInfo | Null = null
override def sourceModule(using Context): TermSymbol = _sourceModule
def description(using Context): String = "package loader " + sourceModule.fullName

Expand Down Expand Up @@ -317,7 +316,7 @@ abstract class SymbolLoader extends LazyType { self =>
/** Load source or class file for `root`, return */
def doComplete(root: SymDenotation)(using Context): Unit

def sourceFileOrNull: AbstractFile | Null
def compilationUnitInfo: CompilationUnitInfo | Null

/** Description of the resource (ClassPath, AbstractFile)
* being processed by this loader
Expand All @@ -328,7 +327,7 @@ abstract class SymbolLoader extends LazyType { self =>
* but provides fresh slots for scope/sourceModule/moduleClass
*/
def proxy: SymbolLoader = new SymbolLoader {
export self.{doComplete, sourceFileOrNull}
export self.{doComplete, compilationUnitInfo}
def description(using Context): String = s"proxy to ${self.description}"
}

Expand Down Expand Up @@ -405,7 +404,8 @@ abstract class SymbolLoader extends LazyType { self =>

class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader {

override def sourceFileOrNull: AbstractFile | Null = classfile
def compilationUnitInfo: CompilationUnitInfo | Null = CompilationUnitInfo(classfile)


def description(using Context): String = "class file " + classfile.toString

Expand All @@ -417,38 +417,55 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader {

class TastyLoader(val tastyFile: AbstractFile) extends SymbolLoader {

override def sourceFileOrNull: AbstractFile | Null = tastyFile
private val unpickler: tasty.DottyUnpickler =
handleUnpicklingExceptions:
val tastyBytes = tastyFile.toByteArray
new tasty.DottyUnpickler(tastyBytes) // reads header and name table

def compilationUnitInfo: CompilationUnitInfo | Null =
bishabosha marked this conversation as resolved.
Show resolved Hide resolved
val tastyHeader = unpickler.unpickler.header
val tastyVersion = TastyVersion(
tastyHeader.majorVersion,
tastyHeader.minorVersion,
tastyHeader.experimentalVersion,
)
val attributes = unpickler.tastyAttributes
new CompilationUnitInfo(
tastyFile,
tastyVersion = Some(tastyVersion),
explicitNulls = attributes.explicitNulls,
)

def description(using Context): String = "TASTy file " + tastyFile.toString

override def doComplete(root: SymDenotation)(using Context): Unit =
try
handleUnpicklingExceptions:
checkTastyUUID()
val (classRoot, moduleRoot) = rootDenots(root.asClass)
val tastyBytes = tastyFile.toByteArray
val unpickler = new tasty.DottyUnpickler(tastyBytes)
unpickler.enter(roots = Set(classRoot, moduleRoot, moduleRoot.sourceModule))(using ctx.withSource(util.NoSource))
if mayLoadTreesFromTasty then
classRoot.classSymbol.rootTreeOrProvider = unpickler
moduleRoot.classSymbol.rootTreeOrProvider = unpickler
checkTastyUUID(tastyFile, tastyBytes)

private def handleUnpicklingExceptions[T](thunk: =>T): T =
try thunk
catch case e: RuntimeException =>
val message = e match
case e: UnpickleException =>
i"""TASTy file ${tastyFile.canonicalPath} could not be read, failing with:
s"""TASTy file ${tastyFile.canonicalPath} could not be read, failing with:
bishabosha marked this conversation as resolved.
Show resolved Hide resolved
| ${Option(e.getMessage).getOrElse("")}"""
case _ =>
i"""TASTy file ${tastyFile.canonicalPath} is broken, reading aborted with ${e.getClass}
s"""TASTy file ${tastyFile.canonicalPath} is broken, reading aborted with ${e.getClass}
| ${Option(e.getMessage).getOrElse("")}"""
if (ctx.debug) e.printStackTrace()
throw IOException(message)
throw IOException(message, e)


private def checkTastyUUID(tastyFile: AbstractFile, tastyBytes: Array[Byte])(using Context): Unit =
private def checkTastyUUID()(using Context): Unit =
val classfile =
val className = tastyFile.name.stripSuffix(".tasty")
tastyFile.resolveSibling(className + ".class")
if classfile != null then
val tastyUUID = new TastyHeaderUnpickler(TastyUnpickler.scala3CompilerConfig, tastyBytes).readHeader()
val tastyUUID = unpickler.unpickler.header.uuid
new ClassfileTastyUUIDParser(classfile)(ctx).checkTastyUUID(tastyUUID)
else
// This will be the case in any of our tests that compile with `-Youtput-only-tasty`
Expand All @@ -460,15 +477,15 @@ class TastyLoader(val tastyFile: AbstractFile) extends SymbolLoader {

class SourcefileLoader(val srcfile: AbstractFile) extends SymbolLoader {
def description(using Context): String = "source file " + srcfile.toString
override def sourceFileOrNull: AbstractFile | Null = srcfile
def compilationUnitInfo: CompilationUnitInfo | Null = CompilationUnitInfo(srcfile)
def doComplete(root: SymDenotation)(using Context): Unit =
ctx.run.nn.lateCompile(srcfile, typeCheck = ctx.settings.YretainTrees.value)
}

/** A NoCompleter which is also a SymbolLoader. */
class NoLoader extends SymbolLoader with NoCompleter {
def description(using Context): String = "NoLoader"
override def sourceFileOrNull: AbstractFile | Null = null
def compilationUnitInfo: CompilationUnitInfo | Null = null
override def complete(root: SymDenotation)(using Context): Unit =
super[NoCompleter].complete(root)
def doComplete(root: SymDenotation)(using Context): Unit =
Expand Down
Loading