aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-03-15 17:10:24 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-03-18 16:06:33 +0100
commit1dbf020c43639b0c37e9005f2692871d39676ac7 (patch)
treeb1855130096b99917845a715344ba6a768ede1fc /src/dotty/tools
parent76ea699ac1a76ee6048d7fe8239d0a1126581429 (diff)
downloaddotty-1dbf020c43639b0c37e9005f2692871d39676ac7.tar.gz
dotty-1dbf020c43639b0c37e9005f2692871d39676ac7.tar.bz2
dotty-1dbf020c43639b0c37e9005f2692871d39676ac7.zip
Refactored denotation transformers
Many small and large changes. Added samplePhase to demonstrate functionality. To test functioning, run the compiler with args tests/pos/uncurry.scala -Ylog:sample,terminal
Diffstat (limited to 'src/dotty/tools')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala4
-rw-r--r--src/dotty/tools/dotc/Run.scala2
-rw-r--r--src/dotty/tools/dotc/config/Printers.scala2
-rw-r--r--src/dotty/tools/dotc/core/Contexts.scala5
-rw-r--r--src/dotty/tools/dotc/core/DenotTransformers.scala44
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala11
-rw-r--r--src/dotty/tools/dotc/core/Periods.scala14
-rw-r--r--src/dotty/tools/dotc/core/Phases.scala53
-rw-r--r--src/dotty/tools/dotc/transform/SamplePhase.scala49
9 files changed, 96 insertions, 88 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 9844557f5..84e11e7ed 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -11,7 +11,9 @@ import dotty.tools.dotc.core.Phases.Phase
class Compiler {
- def phases: List[Phase] = List(new FrontEnd)
+ def phases: List[Phase] = List(
+ new FrontEnd,
+ new transform.SamplePhase)
var runId = 1
def nextRunId = { runId += 1; runId }
diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala
index 160390c4f..89ca45071 100644
--- a/src/dotty/tools/dotc/Run.scala
+++ b/src/dotty/tools/dotc/Run.scala
@@ -30,7 +30,7 @@ class Run(comp: Compiler)(implicit ctx: Context) {
def compileSources(sources: List[SourceFile]) = Stats.monitorHeartBeat {
if (sources forall (_.exists)) {
units = sources map (new CompilationUnit(_))
- for (phase <- ctx.allPhases) {
+ for (phase <- ctx.allPhases.init) {
if (!ctx.reporter.hasErrors)
phase.runOn(units)
}
diff --git a/src/dotty/tools/dotc/config/Printers.scala b/src/dotty/tools/dotc/config/Printers.scala
index e236e34e0..853049b04 100644
--- a/src/dotty/tools/dotc/config/Printers.scala
+++ b/src/dotty/tools/dotc/config/Printers.scala
@@ -23,5 +23,5 @@ object Printers {
val completions = noPrinter
val gadts = noPrinter
val incremental = noPrinter
-
+ val config = noPrinter
} \ No newline at end of file
diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala
index 0d6e341a6..38784ec0c 100644
--- a/src/dotty/tools/dotc/core/Contexts.scala
+++ b/src/dotty/tools/dotc/core/Contexts.scala
@@ -325,6 +325,7 @@ object Contexts {
def withProperty(prop: (String, Any)): this.type = withMoreProperties(moreProperties + prop)
def withPhase(pid: PhaseId): this.type = withPeriod(Period(runId, pid))
+ def withPhase(phase: Phase): this.type = withPhase(phase.id)
def withSetting[T](setting: Setting[T], value: T): this.type =
withSettings(setting.updateIn(sstate, value))
@@ -361,7 +362,6 @@ object Contexts {
* compiler run.
*/
class ContextBase extends ContextState
- with DenotTransformers.DenotTransformerBase
with Denotations.DenotationsBase
with Phases.PhasesBase {
@@ -460,6 +460,9 @@ object Contexts {
/** Phases by id */
private[core] var phases: Array[Phase] = _
+ /** Next denotation transformer id */
+ private[core] var nextTransformerId: Array[Int] = _
+
// Printers state
/** Number of recursive invocations of a show method on cuyrrent stack */
private[dotc] var toTextRecursions = 0
diff --git a/src/dotty/tools/dotc/core/DenotTransformers.scala b/src/dotty/tools/dotc/core/DenotTransformers.scala
index f41f1d171..be85b5877 100644
--- a/src/dotty/tools/dotc/core/DenotTransformers.scala
+++ b/src/dotty/tools/dotc/core/DenotTransformers.scala
@@ -6,62 +6,26 @@ import SymDenotations._
import Contexts._
import Types._
import Denotations._
+import Phases._
import java.lang.AssertionError
import dotty.tools.dotc.util.DotClass
object DenotTransformers {
- trait DenotTransformerBase { self: ContextBase =>
- val denotTransformers = new DenotTransformerGroup
- }
-
/** A transformer group contains a sequence of transformers,
* ordered by the phase where they apply. Transformers are added
* to a group via `install`.
- *
- * There are two transformerGroups in a context base:
- * symTransformers and refTransformers. symTransformers translate
- * full symbol denotations, refTransformers translate only symbol references
- * of type Unique/JointRefDenotation.
*/
- class DenotTransformerGroup {
-
- private val nxTransformer =
- Array.fill[DenotTransformer](MaxPossiblePhaseId + 1)(NoTransformer)
-
- def nextTransformer(pid: PhaseId) = nxTransformer(pid)
-
- def install(pid: PhaseId, transFn: DenotTransformerGroup => DenotTransformer): Unit =
- if ((pid > NoPhaseId) && (nxTransformer(pid).phaseId > pid)) {
- val trans = transFn(this)
- trans._phaseId = pid
- nxTransformer(pid) = transFn(this)
- install(pid - 1, transFn)
- }
-
- /** A sentinel transformer object */
- object NoTransformer extends DenotTransformer(this) {
- _phaseId = MaxPossiblePhaseId + 1
- override def lastPhaseId = phaseId - 1 // TODO JZ Probably off-by-N error here. MO: Don't think so: we want empty validity period.
- def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation =
- unsupported("transform")
- }
- }
/** A transformer transforms denotations at a given phase */
- abstract class DenotTransformer(group: DenotTransformerGroup) extends DotClass {
-
- private[DenotTransformers] var _phaseId: PhaseId = _
-
- /** The phase at the start of which the denotations are transformed */
- def phaseId: PhaseId = _phaseId
+ trait DenotTransformer extends Phase {
/** The last phase during which the transformed denotations are valid */
- def lastPhaseId = group.nextTransformer(phaseId).phaseId - 1
+ def lastPhaseId(implicit ctx: Context) = ctx.nextTransformerId(id + 1)
/** The validity period of the transformer in the given context */
def validFor(implicit ctx: Context): Period =
- Period(ctx.runId, phaseId, lastPhaseId)
+ Period(ctx.runId, id, lastPhaseId)
/** The transformation method */
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index bd1aedd75..b35647ead 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -390,7 +390,6 @@ object Denotations {
if ((symbol eq this.symbol) && (info eq this.info)) this
else newLikeThis(symbol, info)
-
def orElse(that: => SingleDenotation) = if (this.exists) this else that
def altsWith(p: Symbol => Boolean): List[SingleDenotation] =
@@ -518,7 +517,8 @@ object Denotations {
} else {
// not found, cur points to highest existing variant
var startPid = cur.validFor.lastPhaseId + 1
- val transformer = ctx.denotTransformers.nextTransformer(startPid)
+ val transformer = ctx.phases(startPid - 1).asInstanceOf[DenotTransformer]
+ //println(s"transforming with $transformer")
next = transformer.transform(cur).syncWithParents
if (next eq cur)
startPid = cur.validFor.firstPhaseId
@@ -527,20 +527,23 @@ object Denotations {
case next: ClassDenotation => next.resetFlag(Frozen)
case _ =>
}
+ next.nextInRun = cur.nextInRun
cur.nextInRun = next
cur = next
}
cur.validFor = Period(
currentPeriod.runId, startPid, transformer.lastPhaseId)
+ //println(s"new denot: $cur, valid for ${cur.validFor}")
}
} else {
- // currentPeriod < valid; in this case a version must exist
+ // currentPeriod < end of valid; in this case a version must exist
// but to be defensive we check for infinite loop anyway
var cnt = 0
while (!(cur.validFor contains currentPeriod)) {
+ //println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
cur = cur.nextInRun
cnt += 1
- assert(cnt <= MaxPossiblePhaseId, "seems to be a loop in Denotations")
+ assert(cnt <= MaxPossiblePhaseId, s"seems to be a loop in Denotations for $this, currentPeriod = $currentPeriod")
}
}
cur
diff --git a/src/dotty/tools/dotc/core/Periods.scala b/src/dotty/tools/dotc/core/Periods.scala
index 592516531..1c9fbf0c6 100644
--- a/src/dotty/tools/dotc/core/Periods.scala
+++ b/src/dotty/tools/dotc/core/Periods.scala
@@ -27,20 +27,16 @@ abstract class Periods extends DotClass { self: Context =>
/** The period containing the current period where denotations do not change.
* We compute this by taking as first phase the first phase less or equal to
- * the current phase that has the same "nextTransformer". As last phase
- * we take the phaseId of the nextTransformer - 1. This has the advantage that
- * it works even if no transformer is installed other than the sentinel
- * NoTransformer, which is always installed automatically.
+ * the current phase that has the same "nextTransformerId". As last phase
+ * we take the next transformer id following the current phase.
*/
def stablePeriod = {
var first = phaseId
- val transformers = base.denotTransformers
- val nxTrans = transformers.nextTransformer(first)
- while (first - 1 > NoPhaseId &&
- (transformers.nextTransformer(first - 1) eq nxTrans)) {
+ val nxTrans = ctx.base.nextTransformerId(first)
+ while (first - 1 > NoPhaseId && (ctx.base.nextTransformerId(first - 1) == nxTrans)) {
first -= 1
}
- Period(runId, first, nxTrans.phaseId - 1)
+ Period(runId, first, nxTrans)
}
}
diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala
index 14cab9821..81ab7acbf 100644
--- a/src/dotty/tools/dotc/core/Phases.scala
+++ b/src/dotty/tools/dotc/core/Phases.scala
@@ -4,6 +4,9 @@ package core
import Periods._
import Contexts._
import util.DotClass
+import DenotTransformers._
+import Denotations._
+import config.Printers._
trait Phases { self: Context =>
import Phases._
@@ -18,6 +21,8 @@ trait Phases { self: Context =>
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)
@@ -29,12 +34,13 @@ object Phases {
trait PhasesBase { this: ContextBase =>
- def allPhases = phases.tail
+ def allPhases = phases.tail // drop NoPhase at beginning
object NoPhase extends Phase {
override def exists = false
def name = "<no phase>"
def run(implicit ctx: Context): Unit = unsupported("run")
+ def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = unsupported("transform")
}
object SomePhase extends Phase {
@@ -42,14 +48,38 @@ object Phases {
def run(implicit ctx: Context): Unit = unsupported("run")
}
+ /** A sentinel transformer object */
+ class TerminalPhase extends DenotTransformer {
+ def name = "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 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.
*/
- def usePhases(phases: List[Phase]) =
- this.phases = (NoPhase :: phases).toArray
+ def usePhases(phases: List[Phase]) = {
+ this.phases = (NoPhase :: phases ::: new TerminalPhase :: Nil).toArray
+ this.nextTransformerId = new Array[Int](this.phases.length)
+ var i = 0
+ while (i < this.phases.length) {
+ this.phases(i)._id = i
+ i += 1
+ }
+ var lastTransformerId = i
+ while (i > 0) {
+ i -= 1
+ if (this.phases(i).isInstanceOf[DenotTransformer]) lastTransformerId = i
+ nextTransformerId(i) = lastTransformerId
+ }
+ config.println(s"Phases = ${this.phases.deep}")
+ config.println(s"nextTransformId = ${nextTransformerId.deep}")
+ }
final val typerName = "typer"
final val refchecksName = "refchecks"
@@ -69,7 +99,7 @@ object Phases {
def run(implicit ctx: Context): Unit
def runOn(units: List[CompilationUnit])(implicit ctx: Context): Unit =
- for (unit <- units) run(ctx.fresh.withCompilationUnit(unit))
+ for (unit <- units) run(ctx.fresh.withPhase(this).withCompilationUnit(unit))
def description: String = name
@@ -77,22 +107,13 @@ object Phases {
def exists: Boolean = true
- private[this] var idCache = -1
+ private[Phases] var _id = -1
/** 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.
- * Returns -1 if the phase is not installed in the context.
+ * -1 if the phase is not installed in the context.
*/
- def id(implicit ctx: Context) = {
- val id = idCache
- val phases = ctx.phases
- if (idCache >= 0 && idCache < phases.length && (phases(idCache) eq this))
- id
- else {
- idCache = phases indexOf this
- idCache
- }
- }
+ def id = _id
final def <= (that: Phase)(implicit ctx: Context) =
exists && id <= that.id
diff --git a/src/dotty/tools/dotc/transform/SamplePhase.scala b/src/dotty/tools/dotc/transform/SamplePhase.scala
index 137ab2eda..ed4ac113f 100644
--- a/src/dotty/tools/dotc/transform/SamplePhase.scala
+++ b/src/dotty/tools/dotc/transform/SamplePhase.scala
@@ -4,33 +4,52 @@ package transform
import TreeTransforms._
import core.DenotTransformers._
import core.Denotations._
+import core.SymDenotations._
import core.Contexts._
+import core.Types._
import ast.Trees._
import ast.tpd.{Apply, Tree, cpy}
-class SamplePhase extends TreeTransformer {
-
- def init(implicit ctx: Context) = {
- ctx.base.denotTransformers.install(id, new UncurryDenotTransform(_))
- }
-
+class SamplePhase extends TreeTransformer with DenotTransformer {
def name = "sample"
-
def transformations = Array(new UncurryTreeTransform(_, _))
-}
-
-class UncurryDenotTransform(group: DenotTransformerGroup) extends DenotTransformer(group) {
-
- def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ???
+ def uncurry(tp: Type)(implicit ctx: Context): Type = tp match {
+ case tp @ MethodType(pnames1, ptypes1) =>
+ tp.resultType match {
+ case rt @ MethodType(pnames2, ptypes2) =>
+ tp.derivedMethodType(pnames1 ++ pnames2, ptypes1 ++ ptypes2, rt.resultType)
+ case _ =>
+ tp
+ }
+ case tp: PolyType =>
+ tp.derivedPolyType(tp.paramNames, tp.paramBounds, uncurry(tp.resultType))
+ case _ =>
+ tp
+ }
+ def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
+ val info1 = uncurry(ref.info)
+ if (info1 eq ref.info) ref
+ else ref match {
+ case ref: SymDenotation => ref.copySymDenotation(info = info1)
+ case _ => ref.derivedSingleDenotation(ref.symbol, info1)
+ }
+ }
}
class UncurryTreeTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
- tree match {
- case Apply(fn, args) => cpy.Apply(tree, fn, args ++ tree.args)
+ ctx.traceIndented(s"transforming ${tree.show}", show = true) {
+ tree.fun match {
+ case Apply(fn, args) =>
+ def showType(implicit ctx: Context) =
+ ctx.log(s"at ${ctx.phase} ${fn.symbol} has type ${fn.symbol.info.widen.show}")
+ showType
+ ctx.atNextPhase(showType(_))
+ showType
+ cpy.Apply(tree, fn, args ++ tree.args)
case _ => tree
- }
+ }}
} \ No newline at end of file