Skip to content

Transform/erasure #102

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

Merged
merged 13 commits into from
Mar 31, 2014
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
List(new LazyValsCreateCompanionObjects), //force separataion between lazyVals and LVCreateCO
List(new LazyValTranformContext().transformer, new TypeTestsCasts),
List(new LazyValsCreateCompanionObjects, new PatternMatcher), //force separataion between lazyVals and LVCreateCO
List(new LazyValTranformContext().transformer, new Splitter, new TypeTestsCasts),
List(new Erasure),
List(new UncurryTreeTransform)
)
Expand Down
12 changes: 7 additions & 5 deletions src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Contexts._, Periods._, Symbols._, Phases._, Decorators._
import io.PlainFile
import util.{SourceFile, NoSource, Stats, SimpleMap}
import reporting.Reporter
import transform.TreeChecker
import java.io.{BufferedWriter, OutputStreamWriter}
import scala.reflect.io.VirtualFile

Expand Down Expand Up @@ -39,18 +40,19 @@ class Run(comp: Compiler)(implicit ctx: Context) {
for (phase <- phasesToRun) {
if (!ctx.reporter.hasErrors) {
phase.runOn(units)
if (ctx.settings.Xprint.value.containsPhase(phase))
for (unit <- units)
printTree(ctx.fresh.setPhase(phase).setCompilationUnit(unit))
def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit =
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)) foreachUnit(TreeChecker.check)
}
}
}
}

private def printTree(implicit ctx: Context) = {
private def printTree(ctx: Context) = {
val unit = ctx.compilationUnit
println(s"result of $unit after ${ctx.phase}:")
println(unit.tpdTree.show)
println(unit.tpdTree.show(ctx))
}

def compile(sourceCode: String): Unit = {
Expand Down
13 changes: 10 additions & 3 deletions src/dotty/tools/dotc/ast/tpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
import CheckTrees._, Denotations._, Decorators._
import config.Printers._
import typer.ErrorReporting._

/** Some creators for typed trees */
object tpd extends Trees.Instance[Type] with TypedTreeInfo {
Expand Down Expand Up @@ -400,11 +401,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
}

// convert a numeric with a toXXX method
def numericConversion(tree: Tree, numericCls: Symbol)(implicit ctx: Context): Tree = {
def primitiveConversion(tree: Tree, numericCls: Symbol)(implicit ctx: Context): Tree = {
val mname = ("to" + numericCls.name).toTermName
val conversion = tree.tpe member mname
assert(conversion.symbol.exists, s"$tree => $numericCls")
ensureApplied(Select(tree, conversion.symbol.termRef))
if (conversion.symbol.exists)
ensureApplied(Select(tree, conversion.symbol.termRef))
else if (tree.tpe.widen isRef numericCls)
tree
else {
ctx.warning(i"conversion from ${tree.tpe.widen} to ${numericCls.typeRef} will always fail at runtime.")
Throw(New(defn.ClassCastExceptionClass.typeRef, Nil)) withPos tree.pos
}
}

def evalOnce(tree: Tree)(within: Tree => Tree)(implicit ctx: Context) = {
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class ScalaSettings extends Settings.SettingGroup {
val overrideVars = BooleanSetting("-Yoverride-vars", "Allow vars to be overridden.")
val Yhelp = BooleanSetting("-Y", "Print a synopsis of private options.")
val browse = PhasesSetting("-Ybrowse", "Browse the abstract syntax tree after")
val check = PhasesSetting("-Ycheck", "Check the tree at the end of")
val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of")
val YcheckTypedTrees = BooleanSetting("-YcheckTypedTrees", "Check all constructured typed trees for type correctness")
val Yshow = PhasesSetting("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after")
val Xcloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.")
Expand Down
1 change: 0 additions & 1 deletion src/dotty/tools/dotc/config/Settings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ object Settings {
setting
}


def BooleanSetting(name: String, descr: String): Setting[Boolean] =
publish(Setting(name, descr, false))

Expand Down
58 changes: 38 additions & 20 deletions src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,30 @@ object Contexts {
protected def searchHistory_= (searchHistory: SearchHistory) = _searchHistory = searchHistory
def searchHistory: SearchHistory = _searchHistory

private var phasedCtx: Context = _
private var phasedCtxs: Array[Context] = _


/** This context at given phase.
* This method will always return a phase period equal to phaseId, thus will never return squashed phases
*/
final def withPhase(phaseId: PhaseId): Context = {
if (this.phaseId == phaseId) this
else if (phasedCtx.phaseId == phaseId) phasedCtx
else if (phasedCtxs != null && phasedCtxs(phaseId) != null) phasedCtxs(phaseId)
else {
val ctx1 = fresh.setPhase(phaseId)
if (phasedCtx eq this) phasedCtx = ctx1
else {
if (phasedCtxs == null) phasedCtxs = new Array[Context](base.phases.length)
phasedCtxs(phaseId) = ctx1
}
ctx1
}
}

final def withPhase(phase: Phase): Context =
withPhase(phase.id)
/** If -Ydebug is on, the top of the stack trace where this context
* was created, otherwise `null`.
*/
Expand Down Expand Up @@ -266,29 +290,23 @@ object Contexts {
}
*/

/** A fresh clone of this context. */
def fresh: FreshContext = {
val newctx: Context = super.clone.asInstanceOf[FreshContext]
newctx.outer = this
newctx.implicitsCache = null
newctx.setCreationTrace()
// Dotty deviation: Scala2x allows access to private members implicitCache and setCreationTrace
// even from a subclass prefix. Dotty (and Java) do not. It's confirmed as a bug in Scala2x.
newctx.asInstanceOf[FreshContext]
protected def init(outer: Context): this.type = {
this.outer = outer
this.implicitsCache = null
this.phasedCtx = this
this.phasedCtxs = null
setCreationTrace()
this
}
/** A fresh clone of this context. */
def fresh: FreshContext = clone.asInstanceOf[FreshContext].init(this)

final def withOwner(owner: Symbol): Context =
if (owner ne this.owner) fresh.setOwner(owner) else this

final def withMode(mode: Mode): Context =
if (mode != this.mode) fresh.setMode(mode) else this

/**
* This method will always return a phase period equal to phaseId, thus will never return squashed phases
*/
final def withPhase(phaseId: PhaseId): Context =
if (this.phaseId == phaseId) this else fresh.setPhase(phaseId)
final def withPhase(phase: Phase): Context =
if (this.period == phase.period) this else fresh.setPhase(phase)


final def addMode(mode: Mode): Context = withMode(this.mode | mode)
final def maskMode(mode: Mode): Context = withMode(this.mode & mode)
final def retractMode(mode: Mode): Context = withMode(this.mode &~ mode)
Expand All @@ -313,15 +331,15 @@ object Contexts {
def setPeriod(period: Period): this.type = { this.period = period; this }
def setMode(mode: Mode): this.type = { this.mode = mode; this }
def setTyperState(typerState: TyperState): this.type = { this.typerState = typerState; this }
def clearTyperState: this.type = setTyperState(typerState.fresh(isCommittable = true))
def setNewTyperState: this.type = setTyperState(typerState.fresh(isCommittable = true))
def setExploreTyperState: this.type = setTyperState(typerState.fresh(isCommittable = false))
def setPrinterFn(printer: Context => Printer): this.type = { this.printerFn = printer; this }
def setOwner(owner: Symbol): this.type = { assert(owner != NoSymbol); this.owner = owner; this }
def setSettings(sstate: SettingsState): this.type = { this.sstate = sstate; this }
def setCompilationUnit(compilationUnit: CompilationUnit): this.type = { this.compilationUnit = compilationUnit; this }
def setTree(tree: Tree[_ >: Untyped]): this.type = { this.tree = tree; this }
def setScope(scope: Scope): this.type = { this.scope = scope; this }
def clearScope: this.type = { this.scope = newScope; this }
def setNewScope: this.type = { this.scope = newScope; this }
def setTypeAssigner(typeAssigner: TypeAssigner): this.type = { this.typeAssigner = typeAssigner; this }
def setTyper(typer: Typer): this.type = { this.scope = typer.scope; setTypeAssigner(typer) }
def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }
Expand Down
7 changes: 5 additions & 2 deletions src/dotty/tools/dotc/core/Decorators.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Symbols._
import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer
import util.Positions.Position, util.SourcePosition
import collection.mutable.ListBuffer
import dotty.tools.dotc.transform.TreeTransforms._
import scala.language.implicitConversions

/** This object provides useful implicit decorators for types defined elsewhere */
Expand Down Expand Up @@ -127,8 +128,10 @@ object Decorators {
* one of the names in the list of strings.
*/
implicit class PhaseListDecorator(val names: List[String]) extends AnyVal {
def containsPhase(phase: Phase) =
names exists (phase.name.startsWith)
def containsPhase(phase: Phase): Boolean = phase match {
case phase: TreeTransformer => phase.transformations.exists(containsPhase)
case _ => names exists (phase.name.startsWith)
}
}

implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition =
Expand Down
5 changes: 3 additions & 2 deletions src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ class Definitions {
lazy val Object_!= = newMethod(ObjectClass, nme.NE, methOfAny(BooleanType), Final)
lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
lazy val Object_isInstanceOf = newT1EmptyParamsMethod(ObjectClass, nme.isInstanceOf_Ob, _ => BooleanType, Final | Synthetic)
lazy val Object_asInstanceOf = newT1EmptyParamsMethod(ObjectClass, nme.asInstanceOf_Ob, PolyParam(_, 0), Final | Synthetic)
lazy val Object_isInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.isInstanceOf_Ob, _ => BooleanType, Final | Synthetic)
lazy val Object_asInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.asInstanceOf_Ob, PolyParam(_, 0), Final | Synthetic)
lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1,
pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)

Expand Down Expand Up @@ -218,6 +218,7 @@ class Definitions {
lazy val OptionClass = ctx.requiredClass("scala.Option")
lazy val BoxedNumberClass = ctx.requiredClass("java.lang.Number")
lazy val ThrowableClass = ctx.requiredClass("java.lang.Throwable")
lazy val ClassCastExceptionClass = ctx.requiredClass("java.lang.ClassCastException")
lazy val JavaSerializableClass = ctx.requiredClass("java.lang.Serializable")
lazy val ComparableClass = ctx.requiredClass("java.lang.Comparable")
lazy val ProductClass = ctx.requiredClass("scala.Product")
Expand Down
4 changes: 2 additions & 2 deletions src/dotty/tools/dotc/core/Phases.scala
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ object Phases {
postTyperEmmited = true
new PostTyperTransformer {
override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}")
override protected def transformations: Array[TreeTransform] = transforms.toArray
override def transformations: Array[TreeTransform] = transforms.toArray
}
} else new TreeTransformer {
override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}")
override protected def transformations: Array[TreeTransform] = transforms.toArray
override def transformations: Array[TreeTransform] = transforms.toArray
}
squashedPhases += block
block.init(this, phasess(i).head.id, phasess(i).last.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 @@ -147,7 +147,7 @@ object SymDenotations {
myFlags |= Touched

// completions.println(s"completing ${this.debugString}")
try completer.complete(this)
try completer.complete(this)(ctx.withPhase(validFor.firstPhaseId))
catch {
case ex: CyclicReference =>
completions.println(s"error while completing ${this.debugString}")
Expand Down
11 changes: 8 additions & 3 deletions src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import TypeApplications._
/** A decorator that provides methods for modeling type application */
class TypeApplications(val self: Type) extends AnyVal {

def canHaveTypeParams(implicit ctx: Context) = !ctx.erasedTypes || self.isRef(defn.ArrayClass)

/** The type parameters of this type are:
* For a ClassInfo type, the type parameters of its class.
* For a typeref referring to a class, the type parameters of the class.
Expand Down Expand Up @@ -128,7 +130,7 @@ class TypeApplications(val self: Type) extends AnyVal {
defn.hkTrait(args map alwaysZero).typeParams
}

if (args.isEmpty) self
if (args.isEmpty || !canHaveTypeParams) self
else self match {
case tp: TypeRef =>
val tsym = tp.symbol
Expand Down Expand Up @@ -228,8 +230,11 @@ class TypeApplications(val self: Type) extends AnyVal {
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
*/
def translateParameterized(from: ClassSymbol, to: ClassSymbol)(implicit ctx: Context): Type =
if (self derivesFrom from)
RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info)
if (self.derivesFrom(from))
if (canHaveTypeParams)
RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info)
else
to.typeRef
else self

/** If this is an encoding of a (partially) applied type, return its arguments,
Expand Down
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ object Types {
}
lastDenotation = d
lastSymbol = d.symbol
checkedPeriod = ctx.period
d
}

Expand Down
17 changes: 6 additions & 11 deletions src/dotty/tools/dotc/core/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,11 @@ object Erasure {
*/
def transformInfo(sym: Symbol, tp: Type)(implicit ctx: Context): Type = {
val erase = erasureFn(sym is JavaDefined, isSemi = true, sym.isConstructor, wildcardOK = false)
if ((sym eq defn.Object_asInstanceOf) || sym.isType && (sym.owner eq defn.ArrayClass))
sym.info
else if ((sym eq defn.Object_isInstanceOf) || (sym eq defn.ArrayClass.primaryConstructor)) {
val tp @ PolyType(pnames) = sym.info
tp.derivedPolyType(pnames, TypeBounds.empty :: Nil, erase(tp.resultType))
}
else if (sym.isAbstractType)
TypeAlias(WildcardType)
else
erase(tp)
if ((sym eq defn.Object_asInstanceOf) ||
(sym eq defn.Object_isInstanceOf) ||
(sym.owner eq defn.ArrayClass) && (sym.isType || sym.isConstructor)) sym.info
else if (sym.isAbstractType) TypeAlias(WildcardType)
else erase(tp)
}

def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !(
Expand Down Expand Up @@ -120,7 +115,7 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard
case tp: TypeRef =>
val sym = tp.symbol
if (!sym.isClass)
if (sym.owner eq defn.ArrayClass) tp else this(tp.info)
if (sym.exists && (sym.owner eq defn.ArrayClass)) tp else this(tp.info) //!!!!
else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tp)
else eraseNormalClassRef(tp)
case tp: RefinedType =>
Expand Down
Loading