Skip to content

Commit 1dbf020

Browse files
oderskyDarkDimius
authored andcommitted
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
1 parent 76ea699 commit 1dbf020

File tree

11 files changed

+106
-92
lines changed

11 files changed

+106
-92
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import dotty.tools.dotc.core.Phases.Phase
1111

1212
class Compiler {
1313

14-
def phases: List[Phase] = List(new FrontEnd)
14+
def phases: List[Phase] = List(
15+
new FrontEnd,
16+
new transform.SamplePhase)
1517

1618
var runId = 1
1719
def nextRunId = { runId += 1; runId }

src/dotty/tools/dotc/Run.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Run(comp: Compiler)(implicit ctx: Context) {
3030
def compileSources(sources: List[SourceFile]) = Stats.monitorHeartBeat {
3131
if (sources forall (_.exists)) {
3232
units = sources map (new CompilationUnit(_))
33-
for (phase <- ctx.allPhases) {
33+
for (phase <- ctx.allPhases.init) {
3434
if (!ctx.reporter.hasErrors)
3535
phase.runOn(units)
3636
}

src/dotty/tools/dotc/config/Printers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ object Printers {
2323
val completions = noPrinter
2424
val gadts = noPrinter
2525
val incremental = noPrinter
26-
26+
val config = noPrinter
2727
}

src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ object Contexts {
325325
def withProperty(prop: (String, Any)): this.type = withMoreProperties(moreProperties + prop)
326326

327327
def withPhase(pid: PhaseId): this.type = withPeriod(Period(runId, pid))
328+
def withPhase(phase: Phase): this.type = withPhase(phase.id)
328329

329330
def withSetting[T](setting: Setting[T], value: T): this.type =
330331
withSettings(setting.updateIn(sstate, value))
@@ -361,7 +362,6 @@ object Contexts {
361362
* compiler run.
362363
*/
363364
class ContextBase extends ContextState
364-
with DenotTransformers.DenotTransformerBase
365365
with Denotations.DenotationsBase
366366
with Phases.PhasesBase {
367367

@@ -460,6 +460,9 @@ object Contexts {
460460
/** Phases by id */
461461
private[core] var phases: Array[Phase] = _
462462

463+
/** Next denotation transformer id */
464+
private[core] var nextTransformerId: Array[Int] = _
465+
463466
// Printers state
464467
/** Number of recursive invocations of a show method on cuyrrent stack */
465468
private[dotc] var toTextRecursions = 0

src/dotty/tools/dotc/core/DenotTransformers.scala

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,62 +6,26 @@ import SymDenotations._
66
import Contexts._
77
import Types._
88
import Denotations._
9+
import Phases._
910
import java.lang.AssertionError
1011
import dotty.tools.dotc.util.DotClass
1112

1213
object DenotTransformers {
1314

14-
trait DenotTransformerBase { self: ContextBase =>
15-
val denotTransformers = new DenotTransformerGroup
16-
}
17-
1815
/** A transformer group contains a sequence of transformers,
1916
* ordered by the phase where they apply. Transformers are added
2017
* to a group via `install`.
21-
*
22-
* There are two transformerGroups in a context base:
23-
* symTransformers and refTransformers. symTransformers translate
24-
* full symbol denotations, refTransformers translate only symbol references
25-
* of type Unique/JointRefDenotation.
2618
*/
27-
class DenotTransformerGroup {
28-
29-
private val nxTransformer =
30-
Array.fill[DenotTransformer](MaxPossiblePhaseId + 1)(NoTransformer)
31-
32-
def nextTransformer(pid: PhaseId) = nxTransformer(pid)
33-
34-
def install(pid: PhaseId, transFn: DenotTransformerGroup => DenotTransformer): Unit =
35-
if ((pid > NoPhaseId) && (nxTransformer(pid).phaseId > pid)) {
36-
val trans = transFn(this)
37-
trans._phaseId = pid
38-
nxTransformer(pid) = transFn(this)
39-
install(pid - 1, transFn)
40-
}
41-
42-
/** A sentinel transformer object */
43-
object NoTransformer extends DenotTransformer(this) {
44-
_phaseId = MaxPossiblePhaseId + 1
45-
override def lastPhaseId = phaseId - 1 // TODO JZ Probably off-by-N error here. MO: Don't think so: we want empty validity period.
46-
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation =
47-
unsupported("transform")
48-
}
49-
}
5019

5120
/** A transformer transforms denotations at a given phase */
52-
abstract class DenotTransformer(group: DenotTransformerGroup) extends DotClass {
53-
54-
private[DenotTransformers] var _phaseId: PhaseId = _
55-
56-
/** The phase at the start of which the denotations are transformed */
57-
def phaseId: PhaseId = _phaseId
21+
trait DenotTransformer extends Phase {
5822

5923
/** The last phase during which the transformed denotations are valid */
60-
def lastPhaseId = group.nextTransformer(phaseId).phaseId - 1
24+
def lastPhaseId(implicit ctx: Context) = ctx.nextTransformerId(id + 1)
6125

6226
/** The validity period of the transformer in the given context */
6327
def validFor(implicit ctx: Context): Period =
64-
Period(ctx.runId, phaseId, lastPhaseId)
28+
Period(ctx.runId, id, lastPhaseId)
6529

6630
/** The transformation method */
6731
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation

src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,6 @@ object Denotations {
390390
if ((symbol eq this.symbol) && (info eq this.info)) this
391391
else newLikeThis(symbol, info)
392392

393-
394393
def orElse(that: => SingleDenotation) = if (this.exists) this else that
395394

396395
def altsWith(p: Symbol => Boolean): List[SingleDenotation] =
@@ -518,7 +517,8 @@ object Denotations {
518517
} else {
519518
// not found, cur points to highest existing variant
520519
var startPid = cur.validFor.lastPhaseId + 1
521-
val transformer = ctx.denotTransformers.nextTransformer(startPid)
520+
val transformer = ctx.phases(startPid - 1).asInstanceOf[DenotTransformer]
521+
//println(s"transforming with $transformer")
522522
next = transformer.transform(cur).syncWithParents
523523
if (next eq cur)
524524
startPid = cur.validFor.firstPhaseId
@@ -527,20 +527,23 @@ object Denotations {
527527
case next: ClassDenotation => next.resetFlag(Frozen)
528528
case _ =>
529529
}
530+
next.nextInRun = cur.nextInRun
530531
cur.nextInRun = next
531532
cur = next
532533
}
533534
cur.validFor = Period(
534535
currentPeriod.runId, startPid, transformer.lastPhaseId)
536+
//println(s"new denot: $cur, valid for ${cur.validFor}")
535537
}
536538
} else {
537-
// currentPeriod < valid; in this case a version must exist
539+
// currentPeriod < end of valid; in this case a version must exist
538540
// but to be defensive we check for infinite loop anyway
539541
var cnt = 0
540542
while (!(cur.validFor contains currentPeriod)) {
543+
//println(s"searching: $cur at $currentPeriod, valid for ${cur.validFor}")
541544
cur = cur.nextInRun
542545
cnt += 1
543-
assert(cnt <= MaxPossiblePhaseId, "seems to be a loop in Denotations")
546+
assert(cnt <= MaxPossiblePhaseId, s"seems to be a loop in Denotations for $this, currentPeriod = $currentPeriod")
544547
}
545548
}
546549
cur

src/dotty/tools/dotc/core/Periods.scala

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,16 @@ abstract class Periods extends DotClass { self: Context =>
2727

2828
/** The period containing the current period where denotations do not change.
2929
* We compute this by taking as first phase the first phase less or equal to
30-
* the current phase that has the same "nextTransformer". As last phase
31-
* we take the phaseId of the nextTransformer - 1. This has the advantage that
32-
* it works even if no transformer is installed other than the sentinel
33-
* NoTransformer, which is always installed automatically.
30+
* the current phase that has the same "nextTransformerId". As last phase
31+
* we take the next transformer id following the current phase.
3432
*/
3533
def stablePeriod = {
3634
var first = phaseId
37-
val transformers = base.denotTransformers
38-
val nxTrans = transformers.nextTransformer(first)
39-
while (first - 1 > NoPhaseId &&
40-
(transformers.nextTransformer(first - 1) eq nxTrans)) {
35+
val nxTrans = ctx.base.nextTransformerId(first)
36+
while (first - 1 > NoPhaseId && (ctx.base.nextTransformerId(first - 1) == nxTrans)) {
4137
first -= 1
4238
}
43-
Period(runId, first, nxTrans.phaseId - 1)
39+
Period(runId, first, nxTrans)
4440
}
4541
}
4642

src/dotty/tools/dotc/core/Phases.scala

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ package core
44
import Periods._
55
import Contexts._
66
import util.DotClass
7+
import DenotTransformers._
8+
import Denotations._
9+
import config.Printers._
710

811
trait Phases { self: Context =>
912
import Phases._
@@ -18,6 +21,8 @@ trait Phases { self: Context =>
1821
def atPhase[T](phase: Phase)(op: Context => T): T =
1922
atPhase(phase.id)(op)
2023

24+
def atNextPhase[T](op: Context => T): T = atPhase(phase.next)(op)
25+
2126
def atPhaseNotLaterThan[T](limit: Phase)(op: Context => T): T =
2227
if (!limit.exists || phase <= limit) op(this) else atPhase(limit)(op)
2328

@@ -29,27 +34,52 @@ object Phases {
2934

3035
trait PhasesBase { this: ContextBase =>
3136

32-
def allPhases = phases.tail
37+
def allPhases = phases.tail // drop NoPhase at beginning
3338

3439
object NoPhase extends Phase {
3540
override def exists = false
3641
def name = "<no phase>"
3742
def run(implicit ctx: Context): Unit = unsupported("run")
43+
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = unsupported("transform")
3844
}
3945

4046
object SomePhase extends Phase {
4147
def name = "<some phase>"
4248
def run(implicit ctx: Context): Unit = unsupported("run")
4349
}
4450

51+
/** A sentinel transformer object */
52+
class TerminalPhase extends DenotTransformer {
53+
def name = "terminal"
54+
def run(implicit ctx: Context): Unit = unsupported("run")
55+
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation =
56+
unsupported("transform")
57+
override def lastPhaseId(implicit ctx: Context) = id
58+
}
59+
4560
def phaseNamed(name: String) =
4661
phases.find(_.name == name).getOrElse(NoPhase)
4762

4863
/** Use the following phases in the order they are given.
4964
* The list should never contain NoPhase.
5065
*/
51-
def usePhases(phases: List[Phase]) =
52-
this.phases = (NoPhase :: phases).toArray
66+
def usePhases(phases: List[Phase]) = {
67+
this.phases = (NoPhase :: phases ::: new TerminalPhase :: Nil).toArray
68+
this.nextTransformerId = new Array[Int](this.phases.length)
69+
var i = 0
70+
while (i < this.phases.length) {
71+
this.phases(i)._id = i
72+
i += 1
73+
}
74+
var lastTransformerId = i
75+
while (i > 0) {
76+
i -= 1
77+
if (this.phases(i).isInstanceOf[DenotTransformer]) lastTransformerId = i
78+
nextTransformerId(i) = lastTransformerId
79+
}
80+
config.println(s"Phases = ${this.phases.deep}")
81+
config.println(s"nextTransformId = ${nextTransformerId.deep}")
82+
}
5383

5484
final val typerName = "typer"
5585
final val refchecksName = "refchecks"
@@ -69,30 +99,21 @@ object Phases {
6999
def run(implicit ctx: Context): Unit
70100

71101
def runOn(units: List[CompilationUnit])(implicit ctx: Context): Unit =
72-
for (unit <- units) run(ctx.fresh.withCompilationUnit(unit))
102+
for (unit <- units) run(ctx.fresh.withPhase(this).withCompilationUnit(unit))
73103

74104
def description: String = name
75105

76106
def checkable: Boolean = true
77107

78108
def exists: Boolean = true
79109

80-
private[this] var idCache = -1
110+
private[Phases] var _id = -1
81111

82112
/** The sequence position of this phase in the given context where 0
83113
* is reserved for NoPhase and the first real phase is at position 1.
84-
* Returns -1 if the phase is not installed in the context.
114+
* -1 if the phase is not installed in the context.
85115
*/
86-
def id(implicit ctx: Context) = {
87-
val id = idCache
88-
val phases = ctx.phases
89-
if (idCache >= 0 && idCache < phases.length && (phases(idCache) eq this))
90-
id
91-
else {
92-
idCache = phases indexOf this
93-
idCache
94-
}
95-
}
116+
def id = _id
96117

97118
final def <= (that: Phase)(implicit ctx: Context) =
98119
exists && id <= that.id

src/dotty/tools/dotc/transform/SamplePhase.scala

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,52 @@ package transform
44
import TreeTransforms._
55
import core.DenotTransformers._
66
import core.Denotations._
7+
import core.SymDenotations._
78
import core.Contexts._
9+
import core.Types._
810
import ast.Trees._
911
import ast.tpd.{Apply, Tree, cpy}
1012

11-
class SamplePhase extends TreeTransformer {
12-
13-
def init(implicit ctx: Context) = {
14-
ctx.base.denotTransformers.install(id, new UncurryDenotTransform(_))
15-
}
16-
13+
class SamplePhase extends TreeTransformer with DenotTransformer {
1714
def name = "sample"
18-
1915
def transformations = Array(new UncurryTreeTransform(_, _))
2016

21-
}
22-
23-
class UncurryDenotTransform(group: DenotTransformerGroup) extends DenotTransformer(group) {
24-
25-
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ???
17+
def uncurry(tp: Type)(implicit ctx: Context): Type = tp match {
18+
case tp @ MethodType(pnames1, ptypes1) =>
19+
tp.resultType match {
20+
case rt @ MethodType(pnames2, ptypes2) =>
21+
tp.derivedMethodType(pnames1 ++ pnames2, ptypes1 ++ ptypes2, rt.resultType)
22+
case _ =>
23+
tp
24+
}
25+
case tp: PolyType =>
26+
tp.derivedPolyType(tp.paramNames, tp.paramBounds, uncurry(tp.resultType))
27+
case _ =>
28+
tp
29+
}
2630

31+
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
32+
val info1 = uncurry(ref.info)
33+
if (info1 eq ref.info) ref
34+
else ref match {
35+
case ref: SymDenotation => ref.copySymDenotation(info = info1)
36+
case _ => ref.derivedSingleDenotation(ref.symbol, info1)
37+
}
38+
}
2739
}
2840

2941
class UncurryTreeTransform(group: TreeTransformer, idx: Int) extends TreeTransform(group, idx) {
3042

3143
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
32-
tree match {
33-
case Apply(fn, args) => cpy.Apply(tree, fn, args ++ tree.args)
44+
ctx.traceIndented(s"transforming ${tree.show}", show = true) {
45+
tree.fun match {
46+
case Apply(fn, args) =>
47+
def showType(implicit ctx: Context) =
48+
ctx.log(s"at ${ctx.phase} ${fn.symbol} has type ${fn.symbol.info.widen.show}")
49+
showType
50+
ctx.atNextPhase(showType(_))
51+
showType
52+
cpy.Apply(tree, fn, args ++ tree.args)
3453
case _ => tree
35-
}
54+
}}
3655
}

0 commit comments

Comments
 (0)