Skip to content

Skip redundant superclasses\supertraits. #1368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions src/dotty/tools/backend/jvm/CollectSuperCalls.scala
Original file line number Diff line number Diff line change
@@ -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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment explaining what the purpose of this phase is in some details

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I knew that I was missing something important but could not remember what.


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 _ =>
}
}
}
14 changes: 11 additions & 3 deletions src/dotty/tools/backend/jvm/DottyBackendInterface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion src/dotty/tools/backend/jvm/GenBCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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()
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions tests/run/redundantParents.check
Original file line number Diff line number Diff line change
@@ -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()
30 changes: 30 additions & 0 deletions tests/run/redundantParents.scala
Original file line number Diff line number Diff line change
@@ -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)
}
}