diff --git a/compiler/src/dotty/tools/dotc/core/CompilationUnitInfo.scala b/compiler/src/dotty/tools/dotc/core/CompilationUnitInfo.scala index 0c4367b3c7e0..ffad60c81f72 100644 --- a/compiler/src/dotty/tools/dotc/core/CompilationUnitInfo.scala +++ b/compiler/src/dotty/tools/dotc/core/CompilationUnitInfo.scala @@ -12,17 +12,9 @@ import dotty.tools.tasty.TastyVersion */ class CompilationUnitInfo( val associatedFile: AbstractFile, - private var tastyVersionOpt: Option[TastyVersion], + val tastyVersion: Option[TastyVersion], ) { - def tastyVersion: Option[TastyVersion] = tastyVersionOpt - - /** Sets the TASTy version. Used to initialize the TASTy version when - * Loading a TASTy file in TastyLoader. - */ - def initTastyVersion(version: TastyVersion): Unit = - tastyVersionOpt = Some(version) - override def toString(): String = s"CompilationUnitInfo($associatedFile, $tastyVersion)" } @@ -30,4 +22,4 @@ class CompilationUnitInfo( object CompilationUnitInfo: def apply(assocFile: AbstractFile | Null): CompilationUnitInfo | Null = if assocFile == null then null - else new CompilationUnitInfo(assocFile, tastyVersionOpt = None) // TODO use current TASTy version + else new CompilationUnitInfo(assocFile, tastyVersion = None) // TODO use current TASTy version diff --git a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala index 997ef013e09f..c5a88b45aa55 100644 --- a/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/compiler/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -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.* @@ -418,44 +417,54 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader { class TastyLoader(val tastyFile: AbstractFile) extends SymbolLoader { - private val compUnitInfo = new CompilationUnitInfo( - tastyFile, - tastyVersionOpt = None // set on doComplete + private val unpickler: tasty.DottyUnpickler = + handleUnpicklingExceptions: + val tastyBytes = tastyFile.toByteArray + new tasty.DottyUnpickler(tastyBytes) // reads header and name table + + def compilationUnitInfo: CompilationUnitInfo | Null = + val tastyHeader = unpickler.unpickler.header + new CompilationUnitInfo( + tastyFile, + tastyVersion = Some( + TastyVersion( + tastyHeader.majorVersion, + tastyHeader.minorVersion, + tastyHeader.experimentalVersion, + ) + ) ) - def compilationUnitInfo: CompilationUnitInfo | Null = compUnitInfo - 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) - compUnitInfo.initTastyVersion(unpickler.tastyVersion) 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: | ${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` diff --git a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala index 8268d8e3e843..239293372981 100644 --- a/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/tasty/DottyUnpickler.scala @@ -56,13 +56,6 @@ class DottyUnpickler(bytes: Array[Byte], mode: UnpickleMode = UnpickleMode.TopLe private val attributeUnpicklerOpt = unpickler.unpickle(new AttributesSectionUnpickler) private val treeUnpickler = unpickler.unpickle(treeSectionUnpickler(posUnpicklerOpt, commentUnpicklerOpt, attributeUnpicklerOpt)).get - def tastyVersion: TastyVersion = - TastyVersion( - unpickler.header.majorVersion, - unpickler.header.minorVersion, - unpickler.header.experimentalVersion, - ) - /** Enter all toplevel classes and objects into their scopes * @param roots a set of SymDenotations that should be overwritten by unpickling */