aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/dotty/tools/backend/jvm/GenBCode.scala10
-rw-r--r--src/dotty/tools/dotc/CompilationUnit.scala4
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala28
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala1
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala2
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala1
-rw-r--r--src/dotty/tools/dotc/core/pickling/ClassfileParser.scala29
-rw-r--r--src/dotty/tools/dotc/transform/Pickler.scala59
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala2
-rw-r--r--src/scala/annotation/internal/TASTYLongSignature.java12
-rw-r--r--src/scala/annotation/internal/TASTYSignature.java12
-rw-r--r--tests/pos/sepComp/A_1.scala13
-rw-r--r--tests/pos/sepComp/B_2.scala13
14 files changed, 154 insertions, 33 deletions
diff --git a/.gitignore b/.gitignore
index b882858b3..69d86527a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,4 @@ classes/
# Partest
tests/partest-generated/
+/test-classes/
diff --git a/src/dotty/tools/backend/jvm/GenBCode.scala b/src/dotty/tools/backend/jvm/GenBCode.scala
index a53e910ae..221843881 100644
--- a/src/dotty/tools/backend/jvm/GenBCode.scala
+++ b/src/dotty/tools/backend/jvm/GenBCode.scala
@@ -6,7 +6,7 @@ import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Phases.Phase
import scala.collection.mutable
-import scala.tools.asm.{ClassVisitor, MethodVisitor, FieldVisitor}
+import scala.tools.asm.{CustomAttr, ClassVisitor, MethodVisitor, FieldVisitor}
import scala.tools.nsc.Settings
import scala.tools.nsc.backend.jvm._
import dotty.tools.dotc
@@ -27,6 +27,7 @@ import scala.tools.asm
import scala.tools.asm.tree._
import dotty.tools.dotc.util.{Positions, DotClass}
import tpd._
+import StdNames._
import scala.tools.nsc.backend.jvm.opt.LocalOpt
@@ -174,6 +175,13 @@ class GenBCodePipeline(val entryPoints: List[Symbol], val int: DottyBackendInter
val outF = if (needsOutFolder) getOutFolder(claszSymbol, pcb.thisName) else null;
val plainC = pcb.cnode
+ if (claszSymbol.isClass) // @DarkDimius is this test needed here?
+ for (pickler <- ctx.compilationUnit.picklers.get(claszSymbol.asClass)) {
+ val binary = pickler.assembleParts()
+ val dataAttr = new CustomAttr(nme.TASTYATTR.toString, binary)
+ plainC.visitAttribute(dataAttr)
+ }
+
// -------------- bean info class, if needed --------------
val beanC =
if (claszSymbol hasAnnotation int.BeanInfoAttr) {
diff --git a/src/dotty/tools/dotc/CompilationUnit.scala b/src/dotty/tools/dotc/CompilationUnit.scala
index 60e16ec3e..4f8c30aab 100644
--- a/src/dotty/tools/dotc/CompilationUnit.scala
+++ b/src/dotty/tools/dotc/CompilationUnit.scala
@@ -19,11 +19,11 @@ class CompilationUnit(val source: SourceFile) {
def isJava = source.file.name.endsWith(".java")
/**
- * Pickler used to create TASTY sections.
+ * Picklers used to create TASTY sections, indexed by toplevel class to which they belong.
* Sections: Header, ASTs and Positions are populated by `pickler` phase.
* Subsequent phases can add new sections.
*/
- lazy val pickler: TastyPickler = new TastyPickler()
+ var picklers: Map[ClassSymbol, TastyPickler] = Map()
/**
* Addresses in TASTY file of trees, stored by pickling.
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala
index a7f89337c..c6d7e10f7 100644
--- a/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -461,6 +461,34 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
accum(Nil, root)
}
+
+ /** The top level classes in this tree, including only those module classes that
+ * are not a linked class of some other class in the result.
+ */
+ def topLevelClasses(tree: Tree)(implicit ctx: Context): List[ClassSymbol] = tree match {
+ case PackageDef(_, stats) => stats.flatMap(topLevelClasses)
+ case tdef: TypeDef if tdef.symbol.isClass => tdef.symbol.asClass :: Nil
+ case _ => Nil
+ }
+
+ /** The tree containing only the top-level classes and objects matching either `cls` or its companion object */
+ def sliceTopLevel(tree: Tree, cls: ClassSymbol)(implicit ctx: Context): List[Tree] = tree match {
+ case PackageDef(pid, stats) =>
+ cpy.PackageDef(tree)(pid, stats.flatMap(sliceTopLevel(_, cls))) :: Nil
+ case tdef: TypeDef =>
+ val sym = tdef.symbol
+ assert(sym.isClass)
+ if (cls == sym || cls == sym.linkedClass) tdef :: Nil
+ else Nil
+ case vdef: ValDef =>
+ val sym = vdef.symbol
+ assert(sym is Module)
+ if (cls == sym.companionClass || cls == sym.moduleClass) vdef :: Nil
+ else Nil
+ case tree =>
+ tree :: Nil
+ }
+
/** The statement sequence that contains a definition of `sym`, or Nil
* if none was found.
* For a tree to be found, The symbol must have a position and its definition
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 955439413..b856e3190 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -383,6 +383,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
else if (tpw isRef defn.ShortClass) Literal(Constant(0.toShort))
else Literal(Constant(null)).select(defn.Any_asInstanceOf).appliedToType(tpe)
}
+
private class FindLocalDummyAccumulator(cls: ClassSymbol)(implicit ctx: Context) extends TreeAccumulator[Symbol] {
def apply(sym: Symbol, tree: Tree)(implicit ctx: Context) =
if (sym.exists) sym
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 7accf9148..7de254008 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -335,6 +335,8 @@ class Definitions {
lazy val ContravariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.ContravariantBetween")
lazy val ScalaSignatureAnnot = ctx.requiredClass("scala.reflect.ScalaSignature")
lazy val ScalaLongSignatureAnnot = ctx.requiredClass("scala.reflect.ScalaLongSignature")
+ lazy val TASTYSignatureAnnot = ctx.requiredClass("scala.annotation.internal.TASTYSignature")
+ lazy val TASTYLongSignatureAnnot = ctx.requiredClass("scala.annotation.internal.TASTYLongSignature")
lazy val DeprecatedAnnot = ctx.requiredClass("scala.deprecated")
lazy val MigrationAnnot = ctx.requiredClass("scala.annotation.migration")
lazy val AnnotationDefaultAnnot = ctx.requiredClass("dotty.annotation.internal.AnnotationDefault")
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index 0a6c43f4e..829ff8b8f 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -215,6 +215,7 @@ object StdNames {
final val RuntimeParamAnnotationATTR: N = "RuntimeVisibleParameterAnnotations" // RetentionPolicy.RUNTIME (annotations on parameters)
final val ScalaATTR: N = "Scala"
final val ScalaSignatureATTR: N = "ScalaSig"
+ final val TASTYATTR: N = "TASTY"
final val SignatureATTR: N = "Signature"
final val SourceFileATTR: N = "SourceFile"
final val SyntheticATTR: N = "Synthetic"
diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
index 3d47678b7..21c9aa84d 100644
--- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
+++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala
@@ -664,11 +664,17 @@ class ClassfileParser(
i < attrs
}
- def unpickle(bytes: Array[Byte]): Boolean = {
+ def unpickleScala(bytes: Array[Byte]): Boolean = {
new UnPickler(bytes, classRoot, moduleRoot)(ctx).run()
true
}
+ def unpickleTASTY(bytes: Array[Byte]): Boolean = {
+ new DottyUnpickler(bytes)
+ .enter(roots = Set(classRoot, moduleRoot, moduleRoot.sourceModule))
+ true
+ }
+
def parseScalaSigBytes: Array[Byte] = {
val tag = in.nextByte.toChar
assert(tag == STRING_TAG, tag)
@@ -688,6 +694,11 @@ class ClassfileParser(
pool.getBytes(entries.toList)
}
+ if (scan(tpnme.TASTYATTR)) {
+ val attrLen = in.nextInt
+ return unpickleTASTY(in.nextBytes(attrLen))
+ }
+
if (scan(tpnme.RuntimeAnnotationATTR)) {
val attrLen = in.nextInt
val nAnnots = in.nextChar
@@ -698,12 +709,16 @@ class ClassfileParser(
var j = 0
while (j < nArgs) {
val argName = pool.getName(in.nextChar)
- if (attrClass == defn.ScalaSignatureAnnot && argName == nme.bytes)
- return unpickle(parseScalaSigBytes)
- else if (attrClass == defn.ScalaLongSignatureAnnot && argName == nme.bytes)
- return unpickle(parseScalaLongSigBytes)
- else
- parseAnnotArg(skip = true)
+ if (argName == nme.bytes)
+ if (attrClass == defn.ScalaSignatureAnnot)
+ return unpickleScala(parseScalaSigBytes)
+ else if (attrClass == defn.ScalaLongSignatureAnnot)
+ return unpickleScala(parseScalaLongSigBytes)
+ else if (attrClass == defn.TASTYSignatureAnnot)
+ return unpickleTASTY(parseScalaSigBytes)
+ else if (attrClass == defn.TASTYLongSignatureAnnot)
+ return unpickleTASTY(parseScalaLongSigBytes)
+ parseAnnotArg(skip = true)
j += 1
}
i += 1
diff --git a/src/dotty/tools/dotc/transform/Pickler.scala b/src/dotty/tools/dotc/transform/Pickler.scala
index 515dad2aa..c09ba6889 100644
--- a/src/dotty/tools/dotc/transform/Pickler.scala
+++ b/src/dotty/tools/dotc/transform/Pickler.scala
@@ -9,6 +9,8 @@ import config.Printers.{noPrinter, pickling}
import java.io.PrintStream
import Periods._
import Phases._
+import Symbols._
+import Flags.Module
import collection.mutable
/** This phase pickles trees */
@@ -23,28 +25,41 @@ class Pickler extends Phase {
s.close
}
- private val beforePickling = new mutable.HashMap[CompilationUnit, String]
+ private val beforePickling = new mutable.HashMap[ClassSymbol, String]
+
+ /** Drop any elements of this list that are linked module classes of other elements in the list */
+ private def dropCompanionModuleClasses(clss: List[ClassSymbol])(implicit ctx: Context): List[ClassSymbol] = {
+ val companionModuleClasses =
+ clss.filterNot(_ is Module).map(_.linkedClass).filterNot(_.isAbsent)
+ clss.filterNot(companionModuleClasses.contains)
+ }
override def run(implicit ctx: Context): Unit = {
val unit = ctx.compilationUnit
- val tree = unit.tpdTree
pickling.println(i"unpickling in run ${ctx.runId}")
- if (ctx.settings.YtestPickler.value) beforePickling(unit) = tree.show
- val pickler = unit.pickler
- val treePkl = new TreePickler(pickler)
- treePkl.pickle(tree :: Nil)
- unit.addrOfTree = treePkl.buf.addrOfTree
- unit.addrOfSym = treePkl.addrOfSym
- if (tree.pos.exists)
- new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos)
+ for { cls <- dropCompanionModuleClasses(topLevelClasses(unit.tpdTree))
+ tree <- sliceTopLevel(unit.tpdTree, cls) } {
+ if (ctx.settings.YtestPickler.value) beforePickling(cls) = tree.show
+ val pickler = new TastyPickler()
+ unit.picklers += (cls -> pickler)
+ val treePkl = new TreePickler(pickler)
+ treePkl.pickle(tree :: Nil)
+ unit.addrOfTree = treePkl.buf.addrOfTree
+ unit.addrOfSym = treePkl.addrOfSym
+ if (tree.pos.exists)
+ new PositionPickler(pickler, treePkl.buf.addrOfTree).picklePositions(tree :: Nil, tree.pos)
- def rawBytes = // not needed right now, but useful to print raw format.
- unit.pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
- case (row, i) => s"${i}0: ${row.mkString(" ")}"
+ def rawBytes = // not needed right now, but useful to print raw format.
+ pickler.assembleParts().iterator.grouped(10).toList.zipWithIndex.map {
+ case (row, i) => s"${i}0: ${row.mkString(" ")}"
+ }
+ // println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
+ if (pickling ne noPrinter) {
+ println(i"**** pickled info of $cls")
+ new TastyPrinter(pickler.assembleParts()).printContents()
}
- // println(i"rawBytes = \n$rawBytes%\n%") // DEBUG
- if (pickling ne noPrinter) new TastyPrinter(pickler.assembleParts()).printContents()
+ }
}
override def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] = {
@@ -58,23 +73,23 @@ class Pickler extends Phase {
pickling.println(i"testing unpickler at run ${ctx.runId}")
ctx.definitions.init
val unpicklers =
- for (unit <- units) yield {
- val unpickler = new DottyUnpickler(unit.pickler.assembleParts())
+ for (unit <- units; (cls, pickler) <- unit.picklers) yield {
+ val unpickler = new DottyUnpickler(pickler.assembleParts())
unpickler.enter(roots = Set())
- unpickler
+ cls -> unpickler
}
pickling.println("************* entered toplevel ***********")
- for ((unpickler, unit) <- unpicklers zip units) {
+ for ((cls, unpickler) <- unpicklers) {
val unpickled = unpickler.body(readPositions = false)
- testSame(i"$unpickled%\n%", beforePickling(unit), unit)
+ testSame(i"$unpickled%\n%", beforePickling(cls), cls)
}
}
- private def testSame(unpickled: String, previous: String, unit: CompilationUnit)(implicit ctx: Context) =
+ private def testSame(unpickled: String, previous: String, cls: ClassSymbol)(implicit ctx: Context) =
if (previous != unpickled) {
output("before-pickling.txt", previous)
output("after-pickling.txt", unpickled)
- ctx.error(s"""pickling difference for $unit, for details:
+ ctx.error(s"""pickling difference for ${cls.fullName}, for details:
|
| diff before-pickling.txt after-pickling.txt""".stripMargin)
}
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index c5bd70c1e..2ba27d0f4 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -192,7 +192,7 @@ trait Applications extends Compatibility { self: Typer =>
def success = ok
protected def methodType = methType.asInstanceOf[MethodType]
- private def methString: String = s"method ${methRef.name}: ${methType.show}"
+ private def methString: String = i"${methRef.symbol}: ${methType.show}"
/** Re-order arguments to correctly align named arguments */
def reorder[T >: Untyped](args: List[Trees.Tree[T]]): List[Trees.Tree[T]] = {
diff --git a/src/scala/annotation/internal/TASTYLongSignature.java b/src/scala/annotation/internal/TASTYLongSignature.java
new file mode 100644
index 000000000..2278da258
--- /dev/null
+++ b/src/scala/annotation/internal/TASTYLongSignature.java
@@ -0,0 +1,12 @@
+package scala.annotation.internal;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface TASTYLongSignature {
+ public String[] bytes();
+}
diff --git a/src/scala/annotation/internal/TASTYSignature.java b/src/scala/annotation/internal/TASTYSignature.java
new file mode 100644
index 000000000..a6372f008
--- /dev/null
+++ b/src/scala/annotation/internal/TASTYSignature.java
@@ -0,0 +1,12 @@
+package scala.annotation.internal;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface TASTYSignature {
+ public String bytes();
+}
diff --git a/tests/pos/sepComp/A_1.scala b/tests/pos/sepComp/A_1.scala
new file mode 100644
index 000000000..03d574705
--- /dev/null
+++ b/tests/pos/sepComp/A_1.scala
@@ -0,0 +1,13 @@
+package sepComp
+
+class A(y: Int) {
+
+ val x: Int = y
+
+}
+
+object A {
+
+ def apply(x: Int) = new A(22)
+
+}
diff --git a/tests/pos/sepComp/B_2.scala b/tests/pos/sepComp/B_2.scala
new file mode 100644
index 000000000..3a503b352
--- /dev/null
+++ b/tests/pos/sepComp/B_2.scala
@@ -0,0 +1,13 @@
+package sepComp
+
+class B extends A(22) {
+
+ val y: Int = this.x
+
+ val a = A(33)
+
+ println(a.x)
+
+}
+
+