diff options
author | Dmitry Petrashko <dark@d-d.me> | 2015-02-26 14:12:42 +0100 |
---|---|---|
committer | Dmitry Petrashko <dark@d-d.me> | 2015-02-26 14:12:42 +0100 |
commit | 45477e5ba963d1bd992bfab73de0d1cccea9fb82 (patch) | |
tree | 16ebe96e06d122512a3ff2b789b2c5197fdbc693 | |
parent | b94cd57cb5a1228804be61a500e1da5c1c0f74ea (diff) | |
parent | b620e2f0758566b8c0567cc9a37cfa504c4f3532 (diff) | |
download | dotty-45477e5ba963d1bd992bfab73de0d1cccea9fb82.tar.gz dotty-45477e5ba963d1bd992bfab73de0d1cccea9fb82.tar.bz2 dotty-45477e5ba963d1bd992bfab73de0d1cccea9fb82.zip |
Merge pull request #377 from dotty-staging/ycheck-is-a-phase
make Ycheck a phase
-rw-r--r-- | src/dotty/tools/dotc/Compiler.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/Run.scala | 16 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Contexts.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Periods.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Phases.scala | 142 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TreeChecker.scala | 9 |
6 files changed, 127 insertions, 59 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 403aa1157..4d93e1dd8 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -86,7 +86,7 @@ class Compiler { */ def rootContext(implicit ctx: Context): Context = { ctx.definitions.init(ctx) - ctx.usePhases(phases) + ctx.setPhasePlan(phases) val rootScope = new MutableScope val bootstrap = ctx.fresh .setPeriod(Period(nextRunId, FirstPhaseId)) diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala index a182029e6..a8cc01fc8 100644 --- a/src/dotty/tools/dotc/Run.scala +++ b/src/dotty/tools/dotc/Run.scala @@ -40,14 +40,11 @@ class Run(comp: Compiler)(implicit ctx: Context) { */ def compileSources(sources: List[SourceFile]) = Stats.monitorHeartBeat { if (sources forall (_.exists)) { + val phases = ctx.squashPhases(ctx.phasePlan, + ctx.settings.Yskip.value, ctx.settings.YstopBefore.value, ctx.settings.YstopAfter.value, ctx.settings.Ycheck.value) + ctx.usePhases(phases) units = sources map (new CompilationUnit(_)) - def stoppedBefore(phase: Phase) = - ctx.settings.YstopBefore.value.containsPhase(phase) || - ctx.settings.YstopAfter.value.containsPhase(phase.prev) - val phasesToRun = ctx.allPhases.init - .takeWhile(!stoppedBefore(_)) - .filterNot(ctx.settings.Yskip.value.containsPhase(_)) // TODO: skip only subphase - for (phase <- phasesToRun) + for (phase <- ctx.allPhases) if (!ctx.reporter.hasErrors) { if (ctx.settings.verbose.value) println(s"[$phase]") units = phase.runOn(units) @@ -55,10 +52,7 @@ class Run(comp: Compiler)(implicit ctx: Context) { for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit)) if (ctx.settings.Xprint.value.containsPhase(phase)) foreachUnit(printTree) - if (ctx.settings.Ycheck.value.containsPhase(phase) && !ctx.reporter.hasErrors) { - assert(phase.isCheckable, s"phase $phase is not checkable") - foreachUnit(TreeChecker.check(phasesToRun, _)) - } + } } } diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index b11e77ef2..412960983 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -487,13 +487,13 @@ object Contexts { def rootLoader(root: TermSymbol)(implicit ctx: Context): SymbolLoader = platform.rootLoader(root) // Set up some phases to get started */ - usePhases(List(List(SomePhase))) + usePhases(List(SomePhase)) /** The standard definitions */ val definitions = new Definitions def squashed(p: Phase): Phase = { - squashedPhases.find(_.period.containsPhaseId(p.id)).getOrElse(NoPhase) + allPhases.find(_.period.containsPhaseId(p.id)).getOrElse(NoPhase) } } @@ -560,12 +560,15 @@ object Contexts { * of underlying during a controlled operation exists. */ private[core] val pendingUnderlying = new mutable.HashSet[Type] + + private [core] var phasesPlan: List[List[Phase]] = _ + // Phases state /** Phases by id */ private[core] var phases: Array[Phase] = _ - /** Phases with consecutive Transforms groupped into a single phase */ - private [core] var squashedPhases: Array[Phase] = _ + /** Phases with consecutive Transforms groupped into a single phase, Empty array if squashing is disabled */ + private [core] var squashedPhases: Array[Phase] = Array.empty[Phase] /** Next denotation transformer id */ private[core] var nextDenotTransformerId: Array[Int] = _ diff --git a/src/dotty/tools/dotc/core/Periods.scala b/src/dotty/tools/dotc/core/Periods.scala index b4e22bd87..0bdbb94ba 100644 --- a/src/dotty/tools/dotc/core/Periods.scala +++ b/src/dotty/tools/dotc/core/Periods.scala @@ -47,8 +47,8 @@ object Periods { * * sign, always 0 1 bit * runid 21 bits - * last phase id: 5 bits - * #phases before last: 5 bits + * last phase id: 6 bits + * #phases before last: 6 bits * * // Dmitry: sign == 0 isn't actually always true, in some cases phaseId == -1 is used for shifts, that easily creates code < 0 */ @@ -153,7 +153,7 @@ object Periods { final val FirstPhaseId = 1 /** The number of bits needed to encode a phase identifier. */ - final val PhaseWidth = 5 + final val PhaseWidth = 6 final val PhaseMask = (1 << PhaseWidth) - 1 final val MaxPossiblePhaseId = PhaseMask }
\ No newline at end of file diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index 70dd4296a..bf2b34f3c 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -47,7 +47,7 @@ object Phases { this: ContextBase => // drop NoPhase at beginning - def allPhases = squashedPhases.tail + def allPhases = (if (squashedPhases.nonEmpty) squashedPhases else phases).tail object NoPhase extends Phase { override def exists = false @@ -70,68 +70,129 @@ object Phases { 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 */ - private def squashPhases(phasess: List[List[Phase]]): Array[Phase] = { + 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 + + 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 < phasess.length) { - if (phasess(i).length > 1) { - val phasesInBlock: Set[String] = phasess(i).map(_.phaseName).toSet - for(phase<-phasess(i)) { - 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") + + 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 transforms = filteredPhaseBlock.asInstanceOf[List[MiniPhase]].map(_.treeTransform) + val block = new TreeTransformer { + override def phaseName: String = transformations.map(_.phase.phaseName).mkString("TreeTransform:{", ", ", "}") + + override def transformations: Array[TreeTransform] = transforms.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.exists(nm => phaseToAdd.phaseName.contains(nm)) + if (shouldAddYCheck) { + val checker = new TreeChecker + + squashedPhases += checker } - val transforms = phasess(i).asInstanceOf[List[MiniPhase]].map(_.treeTransform) - val block = new TreeTransformer { - override def phaseName: String = transformations.map(_.phase.phaseName).mkString("TreeTransform:{", ", ", "}") - override def transformations: Array[TreeTransform] = transforms.toArray - } - squashedPhases += block - prevPhases ++= phasess(i).map(_.getClazz) - block.init(this, phasess(i).head.id, phasess(i).last.id) - } else { - squashedPhases += phasess(i).head - prevPhases += phasess(i).head.getClazz } + i += 1 } - (NoPhase :: squashedPhases.toList ::: new TerminalPhase :: Nil).toArray + 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[List[Phase]], squash: Boolean = true) = { - phases = (NoPhase :: phasess.flatten ::: new TerminalPhase :: Nil).toArray + def usePhases(phasess: List[Phase], squash: Boolean = true) = { + + val flatPhases = collection.mutable.ListBuffer[Phase]() + + phasess.foreach(p => p match { + case t: TreeTransformer => flatPhases ++= t.transformations.map(_.phase) + 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 i = 0 - while (i < phases.length) { - phases(i).init(this, i) - val unmetPreceedeRequirements = phases(i).runsAfter -- phasesAfter + + var phaseId = 0 + def nextPhaseId = { + phaseId += 1 + phaseId // starting from 1 as NoPhase is 0 + } + + def checkRequirements(p: Phase) = { + val unmetPreceedeRequirements = p.runsAfter -- phasesAfter assert(unmetPreceedeRequirements.isEmpty, - s"phase ${phases(i)} has unmet requirement: ${unmetPreceedeRequirements.mkString(", ")} should precede this phase") - phasesAfter += phases(i).getClazz + s"phase ${p} has unmet requirement: ${unmetPreceedeRequirements.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 transforms = t.transformations + transforms.foreach{ x => + checkRequirements(x.phase) + x.phase.init(this, nextPhaseId)} + t.init(this, transforms.head.phase.id, transforms.last.phase.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 - phases(i) match { + val phase = phases(i) + phase match { case transformer: DenotTransformer => lastTransformerId = i denotTransformers(i) = transformer @@ -141,28 +202,31 @@ object Phases { } if (squash) { - this.squashedPhases = squashPhases(phasess) + this.squashedPhases = (NoPhase :: phasess).toArray } else { this.squashedPhases = this.phases } config.println(s"Phases = ${phases.deep}") - config.println(s"squashedPhases = ${squashedPhases.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]) { - private var myPhase: Phase = NoPhase + var myPhase: Phase = NoPhase def phase = { if (myPhase eq NoPhase) myPhase = phaseOfClass(pclass) myPhase } + cachedPhases += this } private val typerCache = new PhaseCache(classOf[FrontEnd]) diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index 7552f1f54..a72c2f181 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -35,9 +35,16 @@ import scala.util.control.NonFatal * - After typer, identifiers and select nodes refer to terms only (all types should be * represented as TypeTrees then). */ -class TreeChecker { +class TreeChecker extends Phase { import ast.tpd._ + + def phaseName: String = "Ycheck" + + def run(implicit ctx: Context): Unit = { + check(ctx.allPhases, ctx) + } + private def previousPhases(phases: List[Phase])(implicit ctx: Context): List[Phase] = phases match { case (phase: TreeTransformer) :: phases1 => val subPhases = phase.transformations.map(_.phase) |