aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2015-05-02 18:48:08 +0200
committerDmitry Petrashko <dark@d-d.me>2015-05-02 18:48:08 +0200
commitac46a0e4489bba4f76863cc1491bf2b8441ed1cb (patch)
tree35cb0aa59d10931f6201f1069d70172a43228a86 /src/dotty
parent2dbabca38cee0ff27c92a9a7079959b2461c9869 (diff)
parent10a5f9198f03ae5b8dc54f1113f98da585c4e81a (diff)
downloaddotty-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/dotty')
-rw-r--r--src/dotty/tools/dotc/CompilationUnit.scala14
-rw-r--r--src/dotty/tools/dotc/Compiler.scala8
-rw-r--r--src/dotty/tools/dotc/FromTasty.scala102
-rw-r--r--src/dotty/tools/dotc/Run.scala30
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala5
-rw-r--r--src/dotty/tools/dotc/core/SymbolLoaders.scala5
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala74
-rw-r--r--src/dotty/tools/dotc/core/pickling/DottyUnpickler.scala17
-rw-r--r--src/dotty/tools/dotc/core/pickling/PickleFormat.scala2
-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.scala16
-rw-r--r--src/dotty/tools/dotc/core/pickling/TreeUnpickler.scala13
-rw-r--r--src/dotty/tools/dotc/transform/Pickler.scala21
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)
}