Skip to content

Topic/info transforms #72

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ object Trees {
}
}

abstract class TreeTransformer(val cpy: TreeCopier = inst.cpy) {
abstract class TreeMap(val cpy: TreeCopier = inst.cpy) {

def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
case Ident(name) =>
Expand Down
8 changes: 4 additions & 4 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
new DeepFolder(op).apply(z, tree)

def subst(from: List[Symbol], to: List[Symbol])(implicit ctx: Context): ThisTree =
new TreeMapper(typeMap = new ctx.SubstSymMap(from, to)).apply(tree)
new TreeTypeMap(typeMap = new ctx.SubstSymMap(from, to)).apply(tree)

def changeOwner(from: Symbol, to: Symbol)(implicit ctx: Context): ThisTree =
new TreeMapper(ownerMap = (sym => if (sym == from) to else sym)).apply(tree)
new TreeTypeMap(ownerMap = (sym => if (sym == from) to else sym)).apply(tree)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the fact that changeOwner is exposed on Tree, rather than on Symbol. We have some terrible bugs in scalac whereby speculative typechecking (e.g names/defaults) changes the owner of a symbol before bailing out, which breaks the immutability of Trees.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work? Does this create new symbols for deftrees whose owners need to be changed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


def appliedToTypes(targs: List[Type])(implicit ctx: Context): Tree =
if (targs.isEmpty) tree else TypeApply(tree, targs map (TypeTree(_)))
Expand All @@ -344,7 +344,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def tpes: List[Type] = xs map (_.tpe)
}

class TreeMapper(val typeMap: TypeMap = IdentityTypeMap, val ownerMap: Symbol => Symbol = identity _)(implicit ctx: Context) extends TreeTransformer {
class TreeTypeMap(val typeMap: TypeMap = IdentityTypeMap, val ownerMap: Symbol => Symbol = identity _)(implicit ctx: Context) extends TreeMap {
override def transform(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = super.transform {
tree.withType(typeMap(tree.tpe)) match {
case bind: tpd.Bind =>
Expand Down Expand Up @@ -375,7 +375,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {

/** The current tree map composed with a substitution [from -> to] */
def withSubstitution(from: List[Symbol], to: List[Symbol]) =
new TreeMapper(
new TreeTypeMap(
typeMap andThen ((tp: Type) => tp.substSym(from, to)),
ownerMap andThen (from zip to).toMap)
}
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] {
}
}

abstract class UntypedTreeTransformer(cpy: UntypedTreeCopier = untpd.cpy) extends TreeTransformer(cpy) {
abstract class UntypedTreeMap(cpy: UntypedTreeCopier = untpd.cpy) extends TreeMap(cpy) {
override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
case ModuleDef(mods, name, impl) =>
cpy.ModuleDef(tree, mods, name, transformSub(impl))
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/config/Printers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ object Printers {
val completions = noPrinter
val gadts = noPrinter
val incremental = noPrinter

val config = noPrinter
}
5 changes: 4 additions & 1 deletion src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -361,7 +362,6 @@ object Contexts {
* compiler run.
*/
class ContextBase extends ContextState
with Transformers.TransformerBase
with Denotations.DenotationsBase
with Phases.PhasesBase {

Expand Down Expand Up @@ -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
Expand Down
33 changes: 33 additions & 0 deletions src/dotty/tools/dotc/core/DenotTransformers.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package dotty.tools.dotc
package core

import Periods._
import SymDenotations._
import Contexts._
import Types._
import Denotations._
import Phases._
import java.lang.AssertionError
import dotty.tools.dotc.util.DotClass

object DenotTransformers {

/** A transformer group contains a sequence of transformers,
* ordered by the phase where they apply. Transformers are added
* to a group via `install`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This documentation is outdated.

*/

/** A transformer transforms denotations at a given phase */
trait DenotTransformer extends Phase {

/** The last phase during which the transformed denotations are valid */
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, id, lastPhaseId)

/** The transformation method */
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation
}
}
17 changes: 11 additions & 6 deletions src/dotty/tools/dotc/core/Denotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Symbols._
import Types._
import Periods._
import Flags._
import Transformers._
import DenotTransformers._
import Decorators._
import transform.Erasure
import printing.Texts._
Expand Down Expand Up @@ -192,6 +192,9 @@ object Denotations {
def requiredValue(name: PreName)(implicit ctx: Context): TermSymbol =
info.member(name.toTermName).requiredSymbol(_.info.isParameterless).asTerm

def requiredClass(name: PreName)(implicit ctx: Context): ClassSymbol =
info.member(name.toTypeName).requiredSymbol(_.isClass).asClass

/** The denotation that has a type matching `targetType` when seen
* as a member of type `site`, `NoDenotation` if none exists.
*/
Expand Down Expand Up @@ -387,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] =
Expand Down Expand Up @@ -515,8 +517,8 @@ object Denotations {
} else {
// not found, cur points to highest existing variant
var startPid = cur.validFor.lastPhaseId + 1
val transformers = ctx.transformersFor(cur)
val transformer = transformers.nextTransformer(startPid)
val transformer = ctx.phases(startPid - 1).asInstanceOf[DenotTransformer]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If first phase doesn't implement DenotTransformer this line throws exception

//println(s"transforming with $transformer")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lingering debug statement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say leave it in, it's still relatively new code, so we might want to resurrect it at some point.

next = transformer.transform(cur).syncWithParents
if (next eq cur)
startPid = cur.validFor.firstPhaseId
Expand All @@ -525,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}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lingering debug

}
} 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
Expand Down
14 changes: 5 additions & 9 deletions src/dotty/tools/dotc/core/Periods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.symTransformers
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)
}
}

Expand Down
53 changes: 37 additions & 16 deletions src/dotty/tools/dotc/core/Phases.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand All @@ -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)

Expand All @@ -29,27 +34,52 @@ 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 {
def name = "<some phase>"
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"
Expand All @@ -69,30 +99,21 @@ 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

def checkable: Boolean = true

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
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package dotty.tools.dotc
package core

import Periods._, Contexts._, Symbols._, Denotations._, Names._, NameOps._, Annotations._
import Types._, Flags._, Decorators._, Transformers._, StdNames._, Scopes._
import Types._, Flags._, Decorators._, DenotTransformers._, StdNames._, Scopes._
import NameOps._
import Scopes.Scope
import collection.mutable
Expand Down
5 changes: 2 additions & 3 deletions src/dotty/tools/dotc/core/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package dotc
package core

import Periods._
import Transformers._
import Names._
import Scopes._
import Flags._
Expand All @@ -19,7 +18,7 @@ import Annotations._
import util.Positions._
import StdNames._
import NameOps._
import ast.tpd.{TreeMapper, Tree}
import ast.tpd.{TreeTypeMap, Tree}
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
import collection.mutable
import io.AbstractFile
Expand Down Expand Up @@ -278,7 +277,7 @@ trait Symbols { this: Context =>
else {
val copies: List[Symbol] = for (original <- originals) yield
newNakedSymbol[original.ThisName](original.coord)
val treeMap = new TreeMapper(typeMap, ownerMap)
val treeMap = new TreeTypeMap(typeMap, ownerMap)
.withSubstitution(originals, copies)
(originals, copies).zipped foreach {(original, copy) =>
val odenot = original.denot
Expand Down
Loading