aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Stucki <nicolas.stucki@gmail.com>2016-07-05 10:50:47 +0200
committerNicolas Stucki <nicolas.stucki@gmail.com>2016-07-13 10:30:12 +0200
commit468ff9c0fd341395d39eb57959755fb718990035 (patch)
tree4fcdbb476adc8772c70a80e370a0be3786287669
parentbef40b45f6c15bf55fa73ea7923cb4da74cf77d0 (diff)
downloaddotty-468ff9c0fd341395d39eb57959755fb718990035.tar.gz
dotty-468ff9c0fd341395d39eb57959755fb718990035.tar.bz2
dotty-468ff9c0fd341395d39eb57959755fb718990035.zip
Fix #1209: Skip redundant superclasses\supertraits.
-rw-r--r--src/dotty/tools/backend/jvm/CollectSuperCalls.scala37
-rw-r--r--src/dotty/tools/backend/jvm/DottyBackendInterface.scala14
-rw-r--r--src/dotty/tools/backend/jvm/GenBCode.scala10
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--tests/run/redundantParents.check8
-rw-r--r--tests/run/redundantParents.scala30
6 files changed, 97 insertions, 5 deletions
diff --git a/src/dotty/tools/backend/jvm/CollectSuperCalls.scala b/src/dotty/tools/backend/jvm/CollectSuperCalls.scala
new file mode 100644
index 000000000..d19228364
--- /dev/null
+++ b/src/dotty/tools/backend/jvm/CollectSuperCalls.scala
@@ -0,0 +1,37 @@
+package dotty.tools.backend.jvm
+
+import dotty.tools.dotc.ast.tpd._
+import dotty.tools.dotc.ast.Trees
+import dotty.tools.dotc.core.Contexts.Context
+import dotty.tools.dotc.core.Symbols._
+import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo}
+
+/** Collect all super calls except to the parent class.
+ *
+ * This information is used to know if it is safe to remove a redundant mixin class.
+ * A redundant mixin class is one that is implemented by another mixin class. As the
+ * methods in a redundant mixin class could be implemented with a default abstract method,
+ * the redundant mixin class could be required as a parent by the JVM.
+ */
+class CollectSuperCalls extends MiniPhaseTransform {
+
+ def phaseName: String = "collectSuperCalls"
+
+ override def transformSuper(tree: Super)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ tree match {
+ case Trees.Super(qual: This, mix) if mix.nonEmpty =>
+ val classSymbol = qual.symbol.asClass.classSymbol
+ registerSuperCall(classSymbol, tree.tpe.baseClasses.head)
+ case _ =>
+ }
+ super.transformSuper(tree)
+ }
+
+ private def registerSuperCall(sym: ClassSymbol, calls: ClassSymbol)(implicit ctx: Context) = {
+ ctx.genBCodePhase match {
+ case genBCodePhase: GenBCode =>
+ genBCodePhase.registerSuperCall(sym, calls)
+ case _ =>
+ }
+ }
+}
diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
index 23073d317..f42a8eee2 100644
--- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
+++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
@@ -34,8 +34,11 @@ import NameOps._
import StdNames.nme
import NameOps._
import dotty.tools.dotc.core
+import dotty.tools.dotc.core.Names.TypeName
-class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context) extends BackendInterface{
+import scala.annotation.tailrec
+
+class DottyBackendInterface(outputDirectory: AbstractFile, val superCallsMap: Map[Symbol, Set[ClassSymbol]])(implicit ctx: Context) extends BackendInterface{
type Symbol = Symbols.Symbol
type Type = Types.Type
type Tree = tpd.Tree
@@ -738,9 +741,14 @@ class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context
/**
* All interfaces implemented by a class, except for those inherited through the superclass.
- *
+ * Redundant interfaces are removed unless there is a super call to them.
*/
- def superInterfaces: List[Symbol] = decorateSymbol(sym).directlyInheritedTraits
+ def superInterfaces: List[Symbol] = {
+ val directlyInheritedTraits = decorateSymbol(sym).directlyInheritedTraits
+ val allBaseClasses = directlyInheritedTraits.iterator.flatMap(_.symbol.asClass.baseClasses.drop(1)).toSet
+ val superCalls = superCallsMap.getOrElse(sym, Set.empty)
+ directlyInheritedTraits.filter(t => !allBaseClasses(t) || superCalls(t))
+ }
/**
* True for module classes of package level objects. The backend will generate a mirror class for
diff --git a/src/dotty/tools/backend/jvm/GenBCode.scala b/src/dotty/tools/backend/jvm/GenBCode.scala
index e5b227a97..902f73ae2 100644
--- a/src/dotty/tools/backend/jvm/GenBCode.scala
+++ b/src/dotty/tools/backend/jvm/GenBCode.scala
@@ -4,6 +4,7 @@ import dotty.tools.dotc.CompilationUnit
import dotty.tools.dotc.ast.Trees.{ValDef, PackageDef}
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Phases.Phase
+import dotty.tools.dotc.core.Names.TypeName
import scala.collection.mutable
import scala.tools.asm.{CustomAttr, ClassVisitor, MethodVisitor, FieldVisitor}
@@ -41,11 +42,18 @@ class GenBCode extends Phase {
private val entryPoints = new mutable.HashSet[Symbol]()
def registerEntryPoint(sym: Symbol) = entryPoints += sym
+ private val superCallsMap = new mutable.HashMap[Symbol, Set[ClassSymbol]]()
+ def registerSuperCall(sym: Symbol, calls: ClassSymbol) = {
+ val old = superCallsMap.getOrElse(sym, Set.empty)
+ superCallsMap.put(sym, old + calls)
+ }
+
def outputDir(implicit ctx: Context): AbstractFile =
new PlainDirectory(new Directory(new JFile(ctx.settings.d.value)))
def run(implicit ctx: Context): Unit = {
- new GenBCodePipeline(entryPoints.toList, new DottyBackendInterface(outputDir)(ctx))(ctx).run(ctx.compilationUnit.tpdTree)
+ new GenBCodePipeline(entryPoints.toList,
+ new DottyBackendInterface(outputDir, superCallsMap.toMap)(ctx))(ctx).run(ctx.compilationUnit.tpdTree)
entryPoints.clear()
}
}
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index ce9280d82..d447c3826 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -15,7 +15,7 @@ import transform.TreeTransforms.{TreeTransform, TreeTransformer}
import core.DenotTransformers.DenotTransformer
import core.Denotations.SingleDenotation
-import dotty.tools.backend.jvm.{LabelDefs, GenBCode}
+import dotty.tools.backend.jvm.{LabelDefs, GenBCode, CollectSuperCalls}
import dotty.tools.backend.sjs.GenSJSIR
/** The central class of the dotc compiler. The job of a compiler is to create
@@ -92,6 +92,7 @@ class Compiler {
new RestoreScopes), // Repair scopes rendered invalid by moving definitions in prior phases of the group
List(new ExpandPrivate, // Widen private definitions accessed from nested classes
new CollectEntryPoints, // Find classes with main methods
+ new CollectSuperCalls, // Find classes that are called with super
new MoveStatics, // Move static methods to companion classes
new LabelDefs), // Converts calls to labels to jumps
List(new GenSJSIR), // Generate .js code
diff --git a/tests/run/redundantParents.check b/tests/run/redundantParents.check
new file mode 100644
index 000000000..4c7e367ce
--- /dev/null
+++ b/tests/run/redundantParents.check
@@ -0,0 +1,8 @@
+C1 super class: class java.lang.Object
+C1 interfaces: List(interface T2)
+C2 super class: class C1
+C2 interfaces: List(interface T4, interface T5)
+C3 super class: class C1
+C3 interfaces: List(interface T5)
+C4 super class: class C2
+C4 interfaces: List()
diff --git a/tests/run/redundantParents.scala b/tests/run/redundantParents.scala
new file mode 100644
index 000000000..0cd277bbb
--- /dev/null
+++ b/tests/run/redundantParents.scala
@@ -0,0 +1,30 @@
+
+trait T1
+trait T2 extends T1
+trait T3 extends T2
+trait T4 extends T3
+
+trait T5
+
+class C1 extends T2
+class C2 extends C1 with T4 with T5 with T1 with T2
+class C3 extends C1 with T5
+class C4 extends C2 with T5
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val c1 = (new C1).getClass
+ val c2 = (new C2).getClass
+ val c3 = (new C3).getClass
+ val c4 = (new C4).getClass
+
+ println("C1 super class: " + c1.getSuperclass)
+ println("C1 interfaces: " + c1.getInterfaces.toList)
+ println("C2 super class: " + c2.getSuperclass)
+ println("C2 interfaces: " + c2.getInterfaces.toList)
+ println("C3 super class: " + c3.getSuperclass)
+ println("C3 interfaces: " + c3.getInterfaces.toList)
+ println("C4 super class: " + c4.getSuperclass)
+ println("C4 interfaces: " + c4.getInterfaces.toList)
+ }
+}