aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/core/Phases.scala
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-11-02 11:08:28 +0100
committerGuillaume Martres <smarter@ubuntu.com>2016-11-22 01:35:07 +0100
commit8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch)
treea8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/dotc/core/Phases.scala
parent6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff)
downloaddotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.gz
dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.bz2
dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.zip
Move compiler and compiler tests to compiler dir
Diffstat (limited to 'compiler/src/dotty/tools/dotc/core/Phases.scala')
-rw-r--r--compiler/src/dotty/tools/dotc/core/Phases.scala377
1 files changed, 377 insertions, 0 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala
new file mode 100644
index 000000000..222e2235d
--- /dev/null
+++ b/compiler/src/dotty/tools/dotc/core/Phases.scala
@@ -0,0 +1,377 @@
+package dotty.tools.dotc
+package core
+
+import Periods._
+import Contexts._
+import dotty.tools.backend.jvm.{LabelDefs, GenBCode}
+import dotty.tools.dotc.core.Symbols.ClassSymbol
+import util.DotClass
+import DenotTransformers._
+import Denotations._
+import Decorators._
+import config.Printers.config
+import scala.collection.mutable.{ListBuffer, ArrayBuffer}
+import dotty.tools.dotc.transform.TreeTransforms.{TreeTransformer, MiniPhase, TreeTransform}
+import dotty.tools.dotc.transform._
+import Periods._
+import typer.{FrontEnd, RefChecks}
+import ast.tpd
+
+trait Phases {
+ self: Context =>
+
+ import Phases._
+
+ def phase: Phase = base.phases(period.firstPhaseId)
+
+ def phasesStack: List[Phase] =
+ if ((this eq NoContext) || !phase.exists) Nil
+ else phase :: outersIterator.dropWhile(_.phase == phase).next.phasesStack
+
+ /** Execute `op` at given phase */
+ def atPhase[T](phase: Phase)(op: Context => T): T =
+ atPhase(phase.id)(op)
+
+ def atNextPhase[T](op: Context => T): T = atPhase(phase.next)(op)
+
+ def atPhaseNotLaterThan[T](limit: Phase)(op: Context => T): T =
+ if (!limit.exists || phase <= limit) op(this) else atPhase(limit)(op)
+
+ def atPhaseNotLaterThanTyper[T](op: Context => T): T =
+ atPhaseNotLaterThan(base.typerPhase)(op)
+
+ def isAfterTyper: Boolean = base.isAfterTyper(phase)
+}
+
+object Phases {
+
+ trait PhasesBase {
+ this: ContextBase =>
+
+ // drop NoPhase at beginning
+ def allPhases = (if (squashedPhases.nonEmpty) squashedPhases else phases).tail
+
+ object NoPhase extends Phase {
+ override def exists = false
+ def phaseName = "<no phase>"
+ def run(implicit ctx: Context): Unit = unsupported("run")
+ def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = unsupported("transform")
+ }
+
+ object SomePhase extends Phase {
+ def phaseName = "<some phase>"
+ def run(implicit ctx: Context): Unit = unsupported("run")
+ }
+
+ /** A sentinel transformer object */
+ class TerminalPhase extends DenotTransformer {
+ def phaseName = "terminal"
+ def run(implicit ctx: Context): Unit = unsupported("run")
+ def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation =
+ unsupported("transform")
+ override def lastPhaseId(implicit ctx: Context) = id
+ }
+
+ def phasePlan = this.phasesPlan
+ def setPhasePlan(phasess: List[List[Phase]]) = this.phasesPlan = phasess
+
+ /** Squash TreeTransform's beloning to same sublist to a single TreeTransformer
+ * Each TreeTransform gets own period,
+ * whereas a combined TreeTransformer gets period equal to union of periods of it's TreeTransforms
+ */
+ def squashPhases(phasess: List[List[Phase]],
+ phasesToSkip: List[String], stopBeforePhases: List[String], stopAfterPhases: List[String], YCheckAfter: List[String]): List[Phase] = {
+ val squashedPhases = ListBuffer[Phase]()
+ var prevPhases: Set[Class[_ <: Phase]] = Set.empty
+ val YCheckAll = YCheckAfter.contains("all")
+
+ var stop = false
+ val filteredPhases = phasess.map(_.filter { p =>
+ val pstop = stop
+ stop = stop | stopBeforePhases.contains(p.phaseName) | stopAfterPhases.contains(p.phaseName)
+ !(pstop || stopBeforePhases.contains(p.phaseName) || phasesToSkip.contains(p.phaseName))
+ })
+
+ var i = 0
+
+ while (i < filteredPhases.length) {
+ if (filteredPhases(i).nonEmpty) { //could be empty due to filtering
+ val filteredPhaseBlock = filteredPhases(i)
+ val phaseToAdd =
+ if (filteredPhaseBlock.length > 1) {
+ val phasesInBlock: Set[String] = filteredPhaseBlock.map(_.phaseName).toSet
+ for (phase <- filteredPhaseBlock) {
+ phase match {
+ case p: MiniPhase =>
+ val unmetRequirements = p.runsAfterGroupsOf &~ prevPhases
+ assert(unmetRequirements.isEmpty,
+ s"${phase.phaseName} requires ${unmetRequirements.mkString(", ")} to be in different TreeTransformer")
+
+ case _ =>
+ assert(false, s"Only tree transforms can be squashed, ${phase.phaseName} can not be squashed")
+ }
+ }
+ val block = new TreeTransformer {
+ override def phaseName: String = miniPhases.map(_.phaseName).mkString("TreeTransform:{", ", ", "}")
+ override def miniPhases: Array[MiniPhase] = filteredPhaseBlock.asInstanceOf[List[MiniPhase]].toArray
+ }
+ prevPhases ++= filteredPhaseBlock.map(_.getClazz)
+ block
+ } else { // block of a single phase, no squashing
+ val phase = filteredPhaseBlock.head
+ prevPhases += phase.getClazz
+ phase
+ }
+ squashedPhases += phaseToAdd
+ val shouldAddYCheck = YCheckAfter.containsPhase(phaseToAdd) || YCheckAll
+ if (shouldAddYCheck) {
+ val checker = new TreeChecker
+ squashedPhases += checker
+ }
+ }
+
+ i += 1
+ }
+ squashedPhases.toList
+ }
+
+ /** Use the following phases in the order they are given.
+ * The list should never contain NoPhase.
+ * if squashing is enabled, phases in same subgroup will be squashed to single phase.
+ */
+ def usePhases(phasess: List[Phase], squash: Boolean = true) = {
+
+ val flatPhases = collection.mutable.ListBuffer[Phase]()
+
+ phasess.foreach(p => p match {
+ case t: TreeTransformer => flatPhases ++= t.miniPhases
+ case _ => flatPhases += p
+ })
+
+ phases = (NoPhase :: flatPhases.toList ::: new TerminalPhase :: Nil).toArray
+ var phasesAfter:Set[Class[_ <: Phase]] = Set.empty
+ nextDenotTransformerId = new Array[Int](phases.length)
+ denotTransformers = new Array[DenotTransformer](phases.length)
+
+ var phaseId = 0
+ def nextPhaseId = {
+ phaseId += 1
+ phaseId // starting from 1 as NoPhase is 0
+ }
+
+ def checkRequirements(p: Phase) = {
+ val unmetPrecedeRequirements = p.runsAfter -- phasesAfter
+ assert(unmetPrecedeRequirements.isEmpty,
+ s"phase ${p} has unmet requirement: ${unmetPrecedeRequirements.mkString(", ")} should precede this phase")
+ phasesAfter += p.getClazz
+
+ }
+ var i = 0
+
+ while (i < phasess.length) {
+ val phase = phasess(i)
+ phase match {
+ case t: TreeTransformer =>
+ val miniPhases = t.miniPhases
+ miniPhases.foreach{ phase =>
+ checkRequirements(phase)
+ phase.init(this, nextPhaseId)}
+ t.init(this, miniPhases.head.id, miniPhases.last.id)
+ case _ =>
+ phase.init(this, nextPhaseId)
+ checkRequirements(phase)
+ }
+
+ i += 1
+ }
+
+ phases.last.init(this, nextPhaseId) // init terminal phase
+
+ i = phases.length
+ var lastTransformerId = i
+ while (i > 0) {
+ i -= 1
+ val phase = phases(i)
+ phase match {
+ case transformer: DenotTransformer =>
+ lastTransformerId = i
+ denotTransformers(i) = transformer
+ case _ =>
+ }
+ nextDenotTransformerId(i) = lastTransformerId
+ }
+
+ if (squash) {
+ this.squashedPhases = (NoPhase :: phasess).toArray
+ } else {
+ this.squashedPhases = this.phases
+ }
+
+ config.println(s"Phases = ${phases.deep}")
+ config.println(s"nextDenotTransformerId = ${nextDenotTransformerId.deep}")
+ }
+
+ def phaseOfClass(pclass: Class[_]) = phases.find(pclass.isInstance).getOrElse(NoPhase)
+
+ private val cachedPhases = collection.mutable.Set[PhaseCache]()
+ private def cleanPhaseCache = cachedPhases.foreach(_.myPhase = NoPhase)
+
+ /** A cache to compute the phase with given name, which
+ * stores the phase as soon as phaseNamed returns something
+ * different from NoPhase.
+ */
+ private class PhaseCache(pclass: Class[_ <: Phase]) {
+ var myPhase: Phase = NoPhase
+ def phase = {
+ if (myPhase eq NoPhase) myPhase = phaseOfClass(pclass)
+ myPhase
+ }
+ cachedPhases += this
+ }
+
+ private val typerCache = new PhaseCache(classOf[FrontEnd])
+ private val picklerCache = new PhaseCache(classOf[Pickler])
+
+ private val refChecksCache = new PhaseCache(classOf[RefChecks])
+ private val elimRepeatedCache = new PhaseCache(classOf[ElimRepeated])
+ private val extensionMethodsCache = new PhaseCache(classOf[ExtensionMethods])
+ private val erasureCache = new PhaseCache(classOf[Erasure])
+ private val elimErasedValueTypeCache = new PhaseCache(classOf[ElimErasedValueType])
+ private val patmatCache = new PhaseCache(classOf[PatternMatcher])
+ private val lambdaLiftCache = new PhaseCache(classOf[LambdaLift])
+ private val flattenCache = new PhaseCache(classOf[Flatten])
+ private val explicitOuterCache = new PhaseCache(classOf[ExplicitOuter])
+ private val gettersCache = new PhaseCache(classOf[Getters])
+ private val genBCodeCache = new PhaseCache(classOf[GenBCode])
+
+ def typerPhase = typerCache.phase
+ def picklerPhase = picklerCache.phase
+ def refchecksPhase = refChecksCache.phase
+ def elimRepeatedPhase = elimRepeatedCache.phase
+ def extensionMethodsPhase = extensionMethodsCache.phase
+ def erasurePhase = erasureCache.phase
+ def elimErasedValueTypePhase = elimErasedValueTypeCache.phase
+ def patmatPhase = patmatCache.phase
+ def lambdaLiftPhase = lambdaLiftCache.phase
+ def flattenPhase = flattenCache.phase
+ def explicitOuterPhase = explicitOuterCache.phase
+ def gettersPhase = gettersCache.phase
+ def genBCodePhase = genBCodeCache.phase
+
+ def isAfterTyper(phase: Phase): Boolean = phase.id > typerPhase.id
+ }
+
+ trait Phase extends DotClass {
+
+ def phaseName: String
+
+ /** List of names of phases that should precede this phase */
+ def runsAfter: Set[Class[_ <: Phase]] = Set.empty
+
+ def run(implicit ctx: Context): Unit
+
+ def runOn(units: List[CompilationUnit])(implicit ctx: Context): List[CompilationUnit] =
+ units.map { unit =>
+ val unitCtx = ctx.fresh.setPhase(this.start).setCompilationUnit(unit)
+ run(unitCtx)
+ unitCtx.compilationUnit
+ }
+
+ def description: String = phaseName
+
+ /** Output should be checkable by TreeChecker */
+ def isCheckable: Boolean = true
+
+ /** Check what the phase achieves, to be called at any point after it is finished.
+ */
+ def checkPostCondition(tree: tpd.Tree)(implicit ctx: Context): Unit = ()
+
+ /** If set, allow missing or superfluous arguments in applications
+ * and type applications.
+ */
+ def relaxedTyping: Boolean = false
+
+ /** Is this phase the standard typerphase? True for FrontEnd, but
+ * not for other first phases (such as FromTasty). The predicate
+ * is tested in some places that perform checks and corrections. It's
+ * different from isAfterTyper (and cheaper to test).
+ */
+ def isTyper = false
+
+ def exists: Boolean = true
+
+ private var myPeriod: Period = Periods.InvalidPeriod
+ private var myBase: ContextBase = null
+ private var myErasedTypes = false
+ private var myFlatClasses = false
+ private var myRefChecked = false
+ private var mySymbolicRefs = false
+ private var myLabelsReordered = false
+
+
+ /** The sequence position of this phase in the given context where 0
+ * is reserved for NoPhase and the first real phase is at position 1.
+ * -1 if the phase is not installed in the context.
+ */
+ def id = myPeriod.firstPhaseId
+
+ def period = myPeriod
+ def start = myPeriod.firstPhaseId
+ def end = myPeriod.lastPhaseId
+
+ final def erasedTypes = myErasedTypes // Phase is after erasure
+ final def flatClasses = myFlatClasses // Phase is after flatten
+ final def refChecked = myRefChecked // Phase is after RefChecks
+ final def symbolicRefs = mySymbolicRefs // Phase is after ResolveSuper, newly generated TermRefs should be symbolic
+ final def labelsReordered = myLabelsReordered // Phase is after LabelDefs, labels are flattened and owner chains don't mirror this
+
+ protected[Phases] def init(base: ContextBase, start: Int, end:Int): Unit = {
+ if (start >= FirstPhaseId)
+ assert(myPeriod == Periods.InvalidPeriod, s"phase $this has already been used once; cannot be reused")
+ myBase = base
+ myPeriod = Period(NoRunId, start, end)
+ myErasedTypes = prev.getClass == classOf[Erasure] || prev.erasedTypes
+ myFlatClasses = prev.getClass == classOf[Flatten] || prev.flatClasses
+ myRefChecked = prev.getClass == classOf[RefChecks] || prev.refChecked
+ mySymbolicRefs = prev.getClass == classOf[ResolveSuper] || prev.symbolicRefs
+ myLabelsReordered = prev.getClass == classOf[LabelDefs] || prev.labelsReordered
+ }
+
+ protected[Phases] def init(base: ContextBase, id: Int): Unit = init(base, id, id)
+
+ final def <=(that: Phase) =
+ exists && id <= that.id
+
+ final def prev: Phase =
+ if (id > FirstPhaseId) myBase.phases(start - 1) else myBase.NoPhase
+
+ final def next: Phase =
+ if (hasNext) myBase.phases(end + 1) else myBase.NoPhase
+
+ final def hasNext = start >= FirstPhaseId && end + 1 < myBase.phases.length
+
+ final def iterator =
+ Iterator.iterate(this)(_.next) takeWhile (_.hasNext)
+
+ override def toString = phaseName
+ }
+
+ trait NeedsCompanions {
+ def isCompanionNeeded(cls: ClassSymbol)(implicit ctx: Context): Boolean
+ }
+
+ /** Replace all instances of `oldPhaseClass` in `current` phases
+ * by the result of `newPhases` applied to the old phase.
+ */
+ def replace(oldPhaseClass: Class[_ <: Phase], newPhases: Phase => List[Phase], current: List[List[Phase]]): List[List[Phase]] =
+ current.map(_.flatMap(phase =>
+ if (oldPhaseClass.isInstance(phase)) newPhases(phase) else phase :: Nil))
+
+ /** Dotty deviation: getClass yields Class[_], instead of [Class <: <type of receiver>].
+ * We can get back the old behavior using this decorator. We should also use the same
+ * trick for standard getClass.
+ */
+ private implicit class getClassDeco[T](val x: T) extends AnyVal {
+ def getClazz: Class[_ <: T] = x.getClass.asInstanceOf[Class[_ <: T]]
+ }
+}