diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/dotty/tools/backend/jvm/GenBCode.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/CompilationUnit.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 28 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/StdNames.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/pickling/ClassfileParser.scala | 29 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Pickler.scala | 59 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 2 | ||||
-rw-r--r-- | src/scala/annotation/internal/TASTYLongSignature.java | 12 | ||||
-rw-r--r-- | src/scala/annotation/internal/TASTYSignature.java | 12 | ||||
-rw-r--r-- | tests/pos/sepComp/A_1.scala | 13 | ||||
-rw-r--r-- | tests/pos/sepComp/B_2.scala | 13 |
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) + +} + + |