diff options
author | Dmitry Petrashko <dark@d-d.me> | 2015-05-02 18:48:08 +0200 |
---|---|---|
committer | Dmitry Petrashko <dark@d-d.me> | 2015-05-02 18:48:08 +0200 |
commit | ac46a0e4489bba4f76863cc1491bf2b8441ed1cb (patch) | |
tree | 35cb0aa59d10931f6201f1069d70172a43228a86 /src | |
parent | 2dbabca38cee0ff27c92a9a7079959b2461c9869 (diff) | |
parent | 10a5f9198f03ae5b8dc54f1113f98da585c4e81a (diff) | |
download | dotty-ac46a0e4489bba4f76863cc1491bf2b8441ed1cb.tar.gz dotty-ac46a0e4489bba4f76863cc1491bf2b8441ed1cb.tar.bz2 dotty-ac46a0e4489bba4f76863cc1491bf2b8441ed1cb.zip |
Merge pull request #507 from dotty-staging/add/from-tasty
Compile from Tasty
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/CompilationUnit.scala | 14 | ||||
-rw-r--r-- | src/dotty/tools/dotc/Compiler.scala | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/FromTasty.scala | 102 | ||||
-rw-r--r-- | src/dotty/tools/dotc/Run.scala | 30 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/SymbolLoaders.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/ClassfileParser.scala | 74 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala | 17 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/PickleFormat.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala (renamed from src/dotty/tools/dotc/core/pickling/UnPickler.scala) | 8 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/TastyPickler.scala | 16 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala | 13 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Pickler.scala | 21 |
13 files changed, 228 insertions, 87 deletions
diff --git a/src/dotty/tools/dotc/CompilationUnit.scala b/src/dotty/tools/dotc/CompilationUnit.scala index 4f8c30aab..f5899f0f2 100644 --- a/src/dotty/tools/dotc/CompilationUnit.scala +++ b/src/dotty/tools/dotc/CompilationUnit.scala @@ -24,18 +24,4 @@ class CompilationUnit(val source: SourceFile) { * Subsequent phases can add new sections. */ var picklers: Map[ClassSymbol, TastyPickler] = Map() - - /** - * Addresses in TASTY file of trees, stored by pickling. - * Note that trees are checked for reference equality, - * so one can reliably use this function only dirrectly after `pickler` - */ - var addrOfTree: tpd.Tree => Option[Addr] = (_ => None) - - /** - * Addresses in TASTY file of symbols, stored by pickling. - * Note that trees are checked for reference equality, - * so one can reliably use this function only dirrectly after `pickler` - */ - var addrOfSym: Symbol => Option[Addr] = (_ => None) } diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 2b5748229..44e7ac450 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -8,7 +8,7 @@ import Symbols._ import Scopes._ import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks} import reporting.ConsoleReporter -import dotty.tools.dotc.core.Phases.Phase +import Phases.Phase import dotty.tools.dotc.transform._ import dotty.tools.dotc.transform.TreeTransforms.{TreeTransform, TreeTransformer} import dotty.tools.dotc.core.DenotTransformers.DenotTransformer @@ -103,9 +103,13 @@ class Compiler { (start.setRunInfo(new RunInfo(start)) /: defn.RootImports)(addImport) } - def newRun(implicit ctx: Context): Run = { + def reset()(implicit ctx: Context): Unit = { ctx.base.reset() ctx.runInfo.clear() + } + + def newRun(implicit ctx: Context): Run = { + reset() new Run(this)(rootContext) } } diff --git a/src/dotty/tools/dotc/FromTasty.scala b/src/dotty/tools/dotc/FromTasty.scala new file mode 100644 index 000000000..37f6933bf --- /dev/null +++ b/src/dotty/tools/dotc/FromTasty.scala @@ -0,0 +1,102 @@ +/* dotc + * Copyright 2005-2015 LAMP/EPFL + * @author Martin Odersky + */ +package dotty.tools +package dotc + +import core._ +import Contexts._ +import Symbols._ +import SymDenotations._ +import typer.FrontEnd +import Phases.Phase +import util._ +import Decorators._ +import dotty.tools.dotc.transform.Pickler +import pickling.DottyUnpickler +import ast.tpd._ + +/** Compiler for TASTY files. + * Usage: + * + * scala dotty.tools.dotc.FromTasty (option | classname)* + * + * Options are as for dotc. + * Classnames are fully qualified names of top-level classes that need to have a TASTY attribute. + * Example: + * + * scala dotty.tools.dotc.FromTasty -Xprint:front extMethods.T + */ +object FromTasty extends Driver { + override def newCompiler(): Compiler = new TASTYCompiler + + class TASTYCompiler extends Compiler { + + override def phases: List[List[Phase]] = { + val backendPhases = super.phases.dropWhile { + case List(_: Pickler) => false + case _ => true + }.tail + List(new ReadTastyTreesFromClasses) :: backendPhases + } + + override def newRun(implicit ctx: Context): Run = { + reset() + new TASTYRun(this)(rootContext) + } + } + + class TASTYRun(comp: Compiler)(implicit ctx: Context) extends Run(comp) { + override def compile(classNames: List[String]) = { + units = classNames.map(new TASTYCompilationUnit(_)) + compileUnits() + } + } + + class TASTYCompilationUnit(val className: String) extends CompilationUnit(NoSource) { + override def toString = s"class file $className" + } + + object force extends TreeTraverser { + def traverse(tree: Tree)(implicit ctx: Context): Unit = traverseChildren(tree) + } + + class ReadTastyTreesFromClasses extends FrontEnd { + override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = + units.map(readTASTY) + + def readTASTY(unit: CompilationUnit)(implicit ctx: Context): CompilationUnit = unit match { + case unit: TASTYCompilationUnit => + val className = unit.className.toTypeName + val clsd = + if (className.contains('.')) ctx.base.staticRef(className) + else defn.EmptyPackageClass.info.decl(className) + def cannotUnpickle(reason: String) = { + ctx.error(s"class $className cannot be unpickled because $reason") + unit + } + clsd match { + case clsd: ClassDenotation => + clsd.infoOrCompleter match { + case info: ClassfileLoader => + info.load(clsd) match { + case Some(unpickler: DottyUnpickler) => + val (List(unpickled), source) = unpickler.body(readPositions = true) + val unit1 = new CompilationUnit(source) + unit1.tpdTree = unpickled + force.traverse(unit1.tpdTree) + unit1 + case _ => + cannotUnpickle(s"its class file ${info.classfile} does not have a TASTY attribute") + } + case info => + cannotUnpickle(s"its info of type ${info.getClass} is not a ClassfileLoader") + } + case _ => + ctx.error(s"class not found: $className") + unit + } + } + } +} diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala index 3d4cd988e..c99f5efb9 100644 --- a/src/dotty/tools/dotc/Run.scala +++ b/src/dotty/tools/dotc/Run.scala @@ -43,23 +43,25 @@ class Run(comp: Compiler)(implicit ctx: Context) { * or we need to assmeble phases on each run, and take -Yskip, -Ystop into * account. I think the latter would be preferable. */ - def compileSources(sources: List[SourceFile]) = Stats.monitorHeartBeat { + def compileSources(sources: List[SourceFile]) = if (sources forall (_.exists)) { - val phases = ctx.squashPhases(ctx.phasePlan, - ctx.settings.Yskip.value, ctx.settings.YstopBefore.value, ctx.settings.YstopAfter.value, ctx.settings.Ycheck.value) - ctx.usePhases(phases) units = sources map (new CompilationUnit(_)) - for (phase <- ctx.allPhases) - if (!ctx.reporter.hasErrors) { - if (ctx.settings.verbose.value) println(s"[$phase]") - units = phase.runOn(units) - def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit = - for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit)) - if (ctx.settings.Xprint.value.containsPhase(phase)) - foreachUnit(printTree) - - } + compileUnits() } + + protected def compileUnits() = Stats.monitorHeartBeat { + val phases = ctx.squashPhases(ctx.phasePlan, + ctx.settings.Yskip.value, ctx.settings.YstopBefore.value, ctx.settings.YstopAfter.value, ctx.settings.Ycheck.value) + ctx.usePhases(phases) + for (phase <- ctx.allPhases) + if (!ctx.reporter.hasErrors) { + if (ctx.settings.verbose.value) println(s"[$phase]") + units = phase.runOn(units) + def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit = + for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit)) + if (ctx.settings.Xprint.value.containsPhase(phase)) + foreachUnit(printTree) + } } private def printTree(ctx: Context) = { diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 7de254008..3c36b1a1e 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -4,7 +4,7 @@ package core import Types._, Contexts._, Symbols._, Denotations._, SymDenotations._, StdNames._, Names._ import Flags._, Scopes._, Decorators._, NameOps._, util.Positions._ -import pickling.UnPickler.ensureConstructor +import pickling.Scala2Unpickler.ensureConstructor import scala.annotation.{ switch, meta } import scala.collection.{ mutable, immutable } import PartialFunction._ @@ -99,7 +99,8 @@ class Definitions { lazy val RootPackage: TermSymbol = ctx.newSymbol( NoSymbol, nme.ROOTPKG, PackageCreationFlags, TypeRef(NoPrefix, RootClass)) - lazy val EmptyPackageVal = ctx.newCompletePackageSymbol(RootClass, nme.EMPTY_PACKAGE).entered + lazy val EmptyPackageVal = ctx.newPackageSymbol( + RootClass, nme.EMPTY_PACKAGE, (emptypkg, emptycls) => ctx.rootLoader(emptypkg)).entered lazy val EmptyPackageClass = EmptyPackageVal.moduleClass.asClass /** A package in which we can place all methods that are interpreted specially by the compiler */ diff --git a/src/dotty/tools/dotc/core/SymbolLoaders.scala b/src/dotty/tools/dotc/core/SymbolLoaders.scala index 0e8c9a41d..296c4ad1e 100644 --- a/src/dotty/tools/dotc/core/SymbolLoaders.scala +++ b/src/dotty/tools/dotc/core/SymbolLoaders.scala @@ -251,7 +251,10 @@ class ClassfileLoader(val classfile: AbstractFile) extends SymbolLoader { else (rootDenot, linkedDenot) } - def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = { + override def doComplete(root: SymDenotation)(implicit ctx: Context): Unit = + load(root) + + def load(root: SymDenotation)(implicit ctx: Context): Option[ClassfileParser.Embedded] = { val (classRoot, moduleRoot) = rootDenots(root.asClass) new ClassfileParser(classfile, classRoot, moduleRoot)(ctx).run() } diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index 21c9aa84d..918a97476 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -4,7 +4,7 @@ package core package pickling import Contexts._, Symbols._, Types._, Names._, StdNames._, NameOps._, Scopes._, Decorators._ -import SymDenotations._, UnPickler._, Constants._, Annotations._, util.Positions._ +import SymDenotations._, Scala2Unpickler._, Constants._, Annotations._, util.Positions._ import ast.tpd._ import java.io.{ File, IOException } import java.lang.Integer.toHexString @@ -15,12 +15,18 @@ import typer.Checking.checkNonCyclic import io.AbstractFile import scala.util.control.NonFatal +object ClassfileParser { + /** Marker trait for unpicklers that can be embedded in classfiles. */ + trait Embedded +} + class ClassfileParser( classfile: AbstractFile, classRoot: ClassDenotation, moduleRoot: ClassDenotation)(ictx: Context) { import ClassfileConstants._ + import ClassfileParser._ protected val in = new AbstractFileReader(classfile) @@ -41,7 +47,7 @@ class ClassfileParser( private def mismatchError(c: Symbol) = throw new IOException(s"class file '${in.file}' has location not matching its contents: contains $c") - def run()(implicit ctx: Context): Unit = try { + def run()(implicit ctx: Context): Option[Embedded] = try { ctx.debuglog("[class] >> " + classRoot.fullName) parseHeader this.pool = new ConstantPool @@ -80,7 +86,7 @@ class ClassfileParser( var sawPrivateConstructor = false - def parseClass()(implicit ctx: Context): Unit = { + def parseClass()(implicit ctx: Context): Option[Embedded] = { val jflags = in.nextChar val isAnnotation = hasAnnotation(jflags) val sflags = FlagTranslation.classFlags(jflags) @@ -94,8 +100,6 @@ class ClassfileParser( addEnclosingTParams() - if (unpickleOrParseInnerClasses()) return - /** Parse parents for Java classes. For Scala, return AnyRef, since the real type will be unpickled. * Updates the read pointer of 'in'. */ def parseParents: List[Type] = { @@ -114,33 +118,36 @@ class ClassfileParser( superType :: ifaces } - var classInfo: Type = TempClassInfoType(parseParents, instanceScope, classRoot.symbol) + val result = unpickleOrParseInnerClasses() + if (!result.isDefined) { + var classInfo: Type = TempClassInfoType(parseParents, instanceScope, classRoot.symbol) // might be reassigned by later parseAttributes - val staticInfo = TempClassInfoType(List(), staticScope, moduleRoot.symbol) + val staticInfo = TempClassInfoType(List(), staticScope, moduleRoot.symbol) - enterOwnInnerClasses + enterOwnInnerClasses - classRoot.setFlag(sflags) - moduleRoot.setFlag(Flags.JavaDefined | Flags.ModuleClassCreationFlags) - setPrivateWithin(classRoot, jflags) - setPrivateWithin(moduleRoot, jflags) - setPrivateWithin(moduleRoot.sourceModule, jflags) + classRoot.setFlag(sflags) + moduleRoot.setFlag(Flags.JavaDefined | Flags.ModuleClassCreationFlags) + setPrivateWithin(classRoot, jflags) + setPrivateWithin(moduleRoot, jflags) + setPrivateWithin(moduleRoot.sourceModule, jflags) - for (i <- 0 until in.nextChar) parseMember(method = false) - for (i <- 0 until in.nextChar) parseMember(method = true) - classInfo = parseAttributes(classRoot.symbol, classInfo) - if (isAnnotation) addAnnotationConstructor(classInfo) + for (i <- 0 until in.nextChar) parseMember(method = false) + for (i <- 0 until in.nextChar) parseMember(method = true) + classInfo = parseAttributes(classRoot.symbol, classInfo) + if (isAnnotation) addAnnotationConstructor(classInfo) - val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, classRoot, moduleRoot) - if (companionClassMethod.exists) companionClassMethod.entered - val companionModuleMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, moduleRoot, classRoot) - if (companionModuleMethod.exists) companionModuleMethod.entered + val companionClassMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, classRoot, moduleRoot) + if (companionClassMethod.exists) companionClassMethod.entered + val companionModuleMethod = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, moduleRoot, classRoot) + if (companionModuleMethod.exists) companionModuleMethod.entered - setClassInfo(classRoot, classInfo) - setClassInfo(moduleRoot, staticInfo) + setClassInfo(classRoot, classInfo) + setClassInfo(moduleRoot, staticInfo) + } + result } - /** Add type parameters of enclosing classes */ def addEnclosingTParams()(implicit ctx: Context): Unit = { var sym = classRoot.owner @@ -644,7 +651,7 @@ class ClassfileParser( * Restores the old `bp`. * @return true iff classfile is from Scala, so no Java info needs to be read. */ - def unpickleOrParseInnerClasses()(implicit ctx: Context): Boolean = { + def unpickleOrParseInnerClasses()(implicit ctx: Context): Option[Embedded] = { val oldbp = in.bp try { skipSuperclasses() @@ -664,15 +671,16 @@ class ClassfileParser( i < attrs } - def unpickleScala(bytes: Array[Byte]): Boolean = { - new UnPickler(bytes, classRoot, moduleRoot)(ctx).run() - true + def unpickleScala(bytes: Array[Byte]): Some[Embedded] = { + val unpickler = new Scala2Unpickler(bytes, classRoot, moduleRoot)(ctx) + unpickler.run() + Some(unpickler) } - def unpickleTASTY(bytes: Array[Byte]): Boolean = { - new DottyUnpickler(bytes) - .enter(roots = Set(classRoot, moduleRoot, moduleRoot.sourceModule)) - true + def unpickleTASTY(bytes: Array[Byte]): Some[Embedded] = { + val unpickler = new DottyUnpickler(bytes) + unpickler.enter(roots = Set(classRoot, moduleRoot, moduleRoot.sourceModule)) + Some(unpickler) } def parseScalaSigBytes: Array[Byte] = { @@ -739,7 +747,7 @@ class ClassfileParser( } } } - false + None } finally in.bp = oldbp } diff --git a/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala b/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala index 64be68975..2d8f571ec 100644 --- a/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala @@ -7,6 +7,7 @@ import Contexts._, SymDenotations._ import dotty.tools.dotc.ast.tpd import TastyUnpickler._, TastyBuffer._ import util.Positions._ +import util.{SourceFile, NoSource} import PositionUnpickler._ object DottyUnpickler { @@ -18,7 +19,7 @@ object DottyUnpickler { /** A class for unpickling Tasty trees and symbols. * @param bytes the bytearray containing the Tasty file from which we unpickle */ -class DottyUnpickler(bytes: Array[Byte]) { +class DottyUnpickler(bytes: Array[Byte]) extends ClassfileParser.Embedded { import tpd._ private val unpickler = new TastyUnpickler(bytes) @@ -30,14 +31,20 @@ class DottyUnpickler(bytes: Array[Byte]) { def enter(roots: Set[SymDenotation])(implicit ctx: Context): Unit = treeUnpickler.enterTopLevel(roots) - /** The unpickled trees + /** The unpickled trees, and the source file they come from * @param readPositions if true, trees get decorated with position information. */ - def body(readPositions: Boolean = false)(implicit ctx: Context): List[Tree] = { + def body(readPositions: Boolean = false)(implicit ctx: Context): (List[Tree], SourceFile) = { + val source = unpickler.unpickle(new SourceFileUnpickler).getOrElse(NoSource) if (readPositions) - for ((totalRange, positions) <- unpickler.unpickle(new PositionsSectionUnpickler())) + for ((totalRange, positions) <- unpickler.unpickle(new PositionsSectionUnpickler)) treeUnpickler.usePositions(totalRange, positions) - treeUnpickler.unpickle() + (treeUnpickler.unpickle(), source) + } + + private class SourceFileUnpickler extends SectionUnpickler[SourceFile]("Sourcefile") { + def unpickle(reader: TastyReader, tastyName: TastyName.Table) = + new SourceFile(tastyName(reader.readNameRef()).toString, Seq()) } private class TreeSectionUnpickler extends SectionUnpickler[TreeUnpickler]("ASTs") { diff --git a/src/dotty/tools/dotc/core/pickling/PickleFormat.scala b/src/dotty/tools/dotc/core/pickling/PickleFormat.scala index d12a879ba..4f3841212 100644 --- a/src/dotty/tools/dotc/core/pickling/PickleFormat.scala +++ b/src/dotty/tools/dotc/core/pickling/PickleFormat.scala @@ -185,6 +185,8 @@ Note: Tree tags are grouped into 5 categories that determine what follows, and t Category 4 (tags 112-127): tag Nat AST Category 5 (tags 128-255): tag Length <payload> +Standard Section: "Sourcefile" sourcefile_NameRef + Standard Section: "Positions" sourceLength_Nat Assoc* Assoc = addr_Delta offset_Delta offset_Delta? diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala index 3c3ec4a70..5fbb4b57f 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/Scala2Unpickler.scala @@ -24,7 +24,7 @@ import scala.collection.{ mutable, immutable } import scala.collection.mutable.ListBuffer import scala.annotation.switch -object UnPickler { +object Scala2Unpickler { /** Exception thrown if classfile is corrupted */ class BadSignature(msg: String) extends RuntimeException(msg) @@ -147,8 +147,8 @@ object UnPickler { * @param moduleroot the top-level module class which is unpickled, or NoSymbol if inapplicable * @param filename filename associated with bytearray, only used for error messages */ -class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: ClassDenotation)(ictx: Context) - extends PickleBuffer(bytes, 0, -1) { +class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: ClassDenotation)(ictx: Context) + extends PickleBuffer(bytes, 0, -1) with ClassfileParser.Embedded { def showPickled() = { atReadPos(0, () => { @@ -159,7 +159,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: // print("unpickling "); showPickled() // !!! DEBUG - import UnPickler._ + import Scala2Unpickler._ val moduleRoot = moduleClassRoot.sourceModule(ictx).denot(ictx) assert(moduleRoot.isTerm) diff --git a/src/dotty/tools/dotc/core/pickling/TastyPickler.scala b/src/dotty/tools/dotc/core/pickling/TastyPickler.scala index 6bd6f1c44..74cc72b8c 100644 --- a/src/dotty/tools/dotc/core/pickling/TastyPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TastyPickler.scala @@ -7,6 +7,8 @@ import PickleFormat._ import collection.mutable import TastyBuffer._ import java.util.UUID +import core.Symbols.Symbol +import ast.tpd class TastyPickler { @@ -51,4 +53,18 @@ class TastyPickler { assert(all.length == totalSize && all.bytes.length == totalSize, s"totalSize = $totalSize, all.length = ${all.length}, all.bytes.length = ${all.bytes.length}") all.bytes } + + /** + * Addresses in TASTY file of trees, stored by pickling. + * Note that trees are checked for reference equality, + * so one can reliably use this function only directly after `pickler` + */ + var addrOfTree: tpd.Tree => Option[Addr] = (_ => None) + + /** + * Addresses in TASTY file of symbols, stored by pickling. + * Note that trees are checked for reference equality, + * so one can reliably use this function only dirrectly after `pickler` + */ + var addrOfSym: Symbol => Option[Addr] = (_ => None) } diff --git a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala index ba3023ed1..7b143dfad 100644 --- a/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala +++ b/src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala @@ -338,7 +338,7 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { name.isTermName && !name.isConstructorName && !givenFlags.is(ParamOrAccessor) || isAbstractType var flags = givenFlags - if (lacksDefinition) flags |= Deferred + if (lacksDefinition && tag != PARAM) flags |= Deferred if (tag == DEFDEF) flags |= Method if (givenFlags is Module) flags = flags | (if (tag == VALDEF) ModuleCreationFlags else ModuleClassCreationFlags) @@ -860,11 +860,12 @@ class TreeUnpickler(reader: TastyReader, tastyName: TastyName.Table) { } } - private def setNormalized(tree: Tree, parentPos: Position): Unit = { - assert(tree.pos.exists) - val absPos = Position(parentPos.start + offsetToInt(tree.pos.start), parentPos.end - tree.pos.end) - tree.setPosUnchecked(absPos) - } + private def setNormalized(tree: Tree, parentPos: Position): Unit = + tree.setPosUnchecked( + if (tree.pos.exists) + Position(parentPos.start + offsetToInt(tree.pos.start), parentPos.end - tree.pos.end) + else + parentPos) def normalizePos(x: Any, parentPos: Position)(implicit ctx: Context): Unit = traverse(x, parentPos, setNormalized) diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala index c09ba6889..50a419589 100644 --- a/src/dotty/tools/dotc/transform/Pickler.scala +++ b/src/dotty/tools/dotc/transform/Pickler.scala @@ -11,6 +11,7 @@ import Periods._ import Phases._ import Symbols._ import Flags.Module +import util.SourceFile import collection.mutable /** This phase pickles trees */ @@ -45,8 +46,10 @@ class Pickler extends Phase { unit.picklers += (cls -> pickler) val treePkl = new TreePickler(pickler) treePkl.pickle(tree :: Nil) - unit.addrOfTree = treePkl.buf.addrOfTree - unit.addrOfSym = treePkl.addrOfSym + pickler.addrOfTree = treePkl.buf.addrOfTree + pickler.addrOfSym = treePkl.addrOfSym + if (unit.source.exists) + pickleSourcefile(pickler, unit.source) if (tree.pos.exists) new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos) @@ -62,6 +65,12 @@ class Pickler extends Phase { } } + private def pickleSourcefile(pickler: TastyPickler, source: SourceFile): Unit = { + val buf = new TastyBuffer(10) + pickler.newSection("Sourcefile", buf) + buf.writeNat(pickler.nameBuffer.nameIndex(source.file.path).index) + } + override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = { val result = super.runOn(units) if (ctx.settings.YtestPickler.value) @@ -80,16 +89,16 @@ class Pickler extends Phase { } pickling.println("************* entered toplevel ***********") for ((cls, unpickler) <- unpicklers) { - val unpickled = unpickler.body(readPositions = false) - testSame(i"$unpickled%\n%", beforePickling(cls), cls) + val (unpickled, source) = unpickler.body(readPositions = true) + testSame(i"$unpickled%\n%", beforePickling(cls), cls, source) } } - private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(implicit ctx: Context) = + private def testSame(unpickled: String, previous: String, cls: ClassSymbol, source: SourceFile)(implicit ctx: Context) = if (previous != unpickled) { output("before-pickling.txt", previous) output("after-pickling.txt", unpickled) - ctx.error(s"""pickling difference for ${cls.fullName}, for details: + ctx.error(s"""pickling difference for ${cls.fullName} in $source, for details: | | diff before-pickling.txt after-pickling.txt""".stripMargin) } |