aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Phases.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-03-26 16:38:59 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-03-27 12:37:32 +0100
commitce372c540c5a879db5bf9792b3448ca932f503e5 (patch)
tree814a17dae985b4b8add77768de80a3b921602650 /src/dotty/tools/dotc/core/Phases.scala
parent7c5dd005fcb34966b87ccef65e1a51d24da4d7b9 (diff)
downloaddotty-ce372c540c5a879db5bf9792b3448ca932f503e5.tar.gz
dotty-ce372c540c5a879db5bf9792b3448ca932f503e5.tar.bz2
dotty-ce372c540c5a879db5bf9792b3448ca932f503e5.zip
Reworked phases.
Aims 1) next/prev should be context-independent. Phase now stores its ContextBase in a field. 2) More robust handling of phaseNamed and the phase properties erasedTypes, flattened, refchecked, etc. These were previously dependent on when the first call to any of these methods was made, which led to a data race. There is now an init method in phases which centralizes all necessary intialization. It is checked that a phase is initialized only once.
Diffstat (limited to 'src/dotty/tools/dotc/core/Phases.scala')
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala108
1 files changed, 68 insertions, 40 deletions
diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala
index c49d314bc..7ae7b6ad3 100644
--- a/src/dotty/tools/dotc/core/Phases.scala
+++ b/src/dotty/tools/dotc/core/Phases.scala
@@ -45,8 +45,6 @@ object Phases {
// drop NoPhase at beginning
def allPhases = squashedPhases.tail
-
-
object NoPhase extends Phase {
override def exists = false
def name = "<no phase>"
@@ -68,26 +66,23 @@ object Phases {
override def lastPhaseId(implicit ctx: Context) = id
}
- def phaseNamed(name: String) =
- phases.find(_.name == name).getOrElse(NoPhase)
-
/** 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(phases: List[List[Phase]], squash: Boolean = true) = {
- this.phases = (NoPhase :: phases.flatten ::: new TerminalPhase :: Nil).toArray
- this.nextDenotTransformerId = new Array[Int](this.phases.length)
- this.denotTransformers = new Array[DenotTransformer](this.phases.length)
+ def usePhases(phasess: List[List[Phase]], squash: Boolean = false) = {
+ phases = (NoPhase :: phasess.flatten ::: new TerminalPhase :: Nil).toArray
+ nextDenotTransformerId = new Array[Int](phases.length)
+ denotTransformers = new Array[DenotTransformer](phases.length)
var i = 0
- while (i < this.phases.length) {
- this.phases(i)._id = i
+ while (i < phases.length) {
+ phases(i).init(this, i)
i += 1
}
var lastTransformerId = i
while (i > 0) {
i -= 1
- this.phases(i) match {
+ phases(i) match {
case transformer: DenotTransformer =>
lastTransformerId = i
denotTransformers(i) = transformer
@@ -100,11 +95,11 @@ object Phases {
val squashedPhases = ListBuffer[Phase]()
var postTyperEmmited = false
var i = 0
- while (i < phases.length) {
- if (phases(i).length > 1) {
- assert(phases(i).forall(x => x.isInstanceOf[TreeTransform]), "Only tree transforms can be squashed")
+ while (i < phasess.length) {
+ if (phasess(i).length > 1) {
+ assert(phasess(i).forall(x => x.isInstanceOf[TreeTransform]), "Only tree transforms can be squashed")
- val transforms = phases(i).asInstanceOf[List[TreeTransform]]
+ val transforms = phasess(i).asInstanceOf[List[TreeTransform]]
val block =
if (!postTyperEmmited) {
postTyperEmmited = true
@@ -117,8 +112,8 @@ object Phases {
override protected def transformations: Array[TreeTransform] = transforms.toArray
}
squashedPhases += block
- block._id = phases(i).head.id
- } else squashedPhases += phases(i).head
+ block.init(this, phasess(i).head.id)
+ } else squashedPhases += phasess(i).head
i += 1
}
this.squashedPhases = (NoPhase::squashedPhases.toList :::new TerminalPhase :: Nil).toArray
@@ -126,22 +121,41 @@ object Phases {
this.squashedPhases = this.phases
}
- config.println(s"Phases = ${this.phases.deep}")
- config.println(s"squashedPhases = ${this.squashedPhases.deep}")
+ config.println(s"Phases = ${phases.deep}")
+ config.println(s"squashedPhases = ${squashedPhases.deep}")
config.println(s"nextDenotTransformerId = ${nextDenotTransformerId.deep}")
}
- final val typerName = "typer"
- final val refchecksName = "refchecks"
- final val erasureName = "erasure"
- final val flattenName = "flatten"
+ def phaseNamed(name: String) = phases.find(_.name == name).getOrElse(NoPhase)
- lazy val typerPhase = phaseNamed(typerName)
- lazy val refchecksPhase = phaseNamed(refchecksName)
- lazy val erasurePhase = phaseNamed(erasureName)
- lazy val flattenPhase = phaseNamed(flattenName)
+ /** 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(name: String) {
+ private var myPhase: Phase = NoPhase
+ def phase = {
+ if (myPhase eq NoPhase) myPhase = phaseNamed(name)
+ myPhase
+ }
+ }
+
+ private val typerCache = new PhaseCache(typerName)
+ private val refChecksCache = new PhaseCache(refChecksName)
+ private val erasureCache = new PhaseCache(erasureName)
+ private val flattenCache = new PhaseCache(flattenName)
+
+ def typerPhase = typerCache.phase
+ def refchecksPhase = refChecksCache.phase
+ def erasurePhase = erasureCache.phase
+ def flattenPhase = flattenCache.phase
}
+ final val typerName = "typer"
+ final val refChecksName = "refchecks"
+ final val erasureName = "erasure"
+ final val flattenName = "flatten"
+
abstract class Phase extends DotClass {
def name: String
@@ -157,32 +171,46 @@ object Phases {
def exists: Boolean = true
- private[Phases] var _id = -1
+ private var myId: PhaseId = -1
+ private var myBase: ContextBase = null
+ private var myErasedTypes = false
+ private var myFlatClasses = false
+ private var myRefChecked = 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 = _id
+ def id = myId
+
+ final def erasedTypes = myErasedTypes
+ final def flatClasses = myFlatClasses
+ final def refChecked = myRefChecked
+
+ protected[Phases] def init(base: ContextBase, id: Int): Unit = {
+ if (id >= FirstPhaseId)
+ assert(myId == -1, s"phase $this has already been used once; cannot be reused")
+ myBase = base
+ myId = id
+ myErasedTypes = prev.name == erasureName || prev.erasedTypes
+ myFlatClasses = prev.name == flattenName || prev.flatClasses
+ myRefChecked = prev.name == refChecksName || prev.refChecked
+ }
final def <=(that: Phase)(implicit ctx: Context) =
exists && id <= that.id
- final def prev(implicit ctx: Context): Phase =
- if (id > FirstPhaseId) ctx.phases(id - 1) else ctx.NoPhase
+ final def prev: Phase =
+ if (id > FirstPhaseId) myBase.phases(id - 1) else myBase.NoPhase
- final def next(implicit ctx: Context): Phase =
- if (hasNext) ctx.phases(id + 1) else ctx.NoPhase
+ final def next: Phase =
+ if (hasNext) myBase.phases(id + 1) else myBase.NoPhase
- final def hasNext(implicit ctx: Context) = id + 1 < ctx.phases.length
+ final def hasNext = id >= FirstPhaseId && id + 1 < myBase.phases.length
- final def iterator(implicit ctx: Context) =
+ final def iterator =
Iterator.iterate(this)(_.next) takeWhile (_.hasNext)
- final def erasedTypes(implicit ctx: Context): Boolean = ctx.erasurePhase <= this
- final def flatClasses(implicit ctx: Context): Boolean = ctx.flattenPhase <= this
- final def refChecked(implicit ctx: Context): Boolean = ctx.refchecksPhase <= this
-
override def toString = name
}
} \ No newline at end of file