Skip to content

Commit e448049

Browse files
committed
Merge pull request #102 from dotty-staging/transform/erasure
Transform/erasure
2 parents 3335cd0 + fb9a9e6 commit e448049

28 files changed

+433
-244
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ class Compiler {
2020
def phases: List[List[Phase]] =
2121
List(
2222
List(new FrontEnd),
23-
List(new LazyValsCreateCompanionObjects), //force separataion between lazyVals and LVCreateCO
24-
List(new LazyValTranformContext().transformer, new TypeTestsCasts),
23+
List(new LazyValsCreateCompanionObjects, new PatternMatcher), //force separataion between lazyVals and LVCreateCO
24+
List(new LazyValTranformContext().transformer, new Splitter, new TypeTestsCasts),
2525
List(new Erasure),
2626
List(new UncurryTreeTransform)
2727
)

src/dotty/tools/dotc/Run.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Contexts._, Periods._, Symbols._, Phases._, Decorators._
66
import io.PlainFile
77
import util.{SourceFile, NoSource, Stats, SimpleMap}
88
import reporting.Reporter
9+
import transform.TreeChecker
910
import java.io.{BufferedWriter, OutputStreamWriter}
1011
import scala.reflect.io.VirtualFile
1112

@@ -39,18 +40,19 @@ class Run(comp: Compiler)(implicit ctx: Context) {
3940
for (phase <- phasesToRun) {
4041
if (!ctx.reporter.hasErrors) {
4142
phase.runOn(units)
42-
if (ctx.settings.Xprint.value.containsPhase(phase))
43-
for (unit <- units)
44-
printTree(ctx.fresh.setPhase(phase).setCompilationUnit(unit))
43+
def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit =
44+
for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
45+
if (ctx.settings.Xprint.value.containsPhase(phase)) foreachUnit(printTree)
46+
if (ctx.settings.Ycheck.value.containsPhase(phase)) foreachUnit(TreeChecker.check)
4547
}
4648
}
4749
}
4850
}
4951

50-
private def printTree(implicit ctx: Context) = {
52+
private def printTree(ctx: Context) = {
5153
val unit = ctx.compilationUnit
5254
println(s"result of $unit after ${ctx.phase}:")
53-
println(unit.tpdTree.show)
55+
println(unit.tpdTree.show(ctx))
5456
}
5557

5658
def compile(sourceCode: String): Unit = {

src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
77
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
88
import CheckTrees._, Denotations._, Decorators._
99
import config.Printers._
10+
import typer.ErrorReporting._
1011

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

402403
// convert a numeric with a toXXX method
403-
def numericConversion(tree: Tree, numericCls: Symbol)(implicit ctx: Context): Tree = {
404+
def primitiveConversion(tree: Tree, numericCls: Symbol)(implicit ctx: Context): Tree = {
404405
val mname = ("to" + numericCls.name).toTermName
405406
val conversion = tree.tpe member mname
406-
assert(conversion.symbol.exists, s"$tree => $numericCls")
407-
ensureApplied(Select(tree, conversion.symbol.termRef))
407+
if (conversion.symbol.exists)
408+
ensureApplied(Select(tree, conversion.symbol.termRef))
409+
else if (tree.tpe.widen isRef numericCls)
410+
tree
411+
else {
412+
ctx.warning(i"conversion from ${tree.tpe.widen} to ${numericCls.typeRef} will always fail at runtime.")
413+
Throw(New(defn.ClassCastExceptionClass.typeRef, Nil)) withPos tree.pos
414+
}
408415
}
409416

410417
def evalOnce(tree: Tree)(within: Tree => Tree)(implicit ctx: Context) = {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class ScalaSettings extends Settings.SettingGroup {
9797
val overrideVars = BooleanSetting("-Yoverride-vars", "Allow vars to be overridden.")
9898
val Yhelp = BooleanSetting("-Y", "Print a synopsis of private options.")
9999
val browse = PhasesSetting("-Ybrowse", "Browse the abstract syntax tree after")
100-
val check = PhasesSetting("-Ycheck", "Check the tree at the end of")
100+
val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of")
101101
val YcheckTypedTrees = BooleanSetting("-YcheckTypedTrees", "Check all constructured typed trees for type correctness")
102102
val Yshow = PhasesSetting("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after")
103103
val Xcloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.")

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@ object Settings {
223223
setting
224224
}
225225

226-
227226
def BooleanSetting(name: String, descr: String): Setting[Boolean] =
228227
publish(Setting(name, descr, false))
229228

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

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,30 @@ object Contexts {
181181
protected def searchHistory_= (searchHistory: SearchHistory) = _searchHistory = searchHistory
182182
def searchHistory: SearchHistory = _searchHistory
183183

184+
private var phasedCtx: Context = _
185+
private var phasedCtxs: Array[Context] = _
186+
187+
188+
/** This context at given phase.
189+
* This method will always return a phase period equal to phaseId, thus will never return squashed phases
190+
*/
191+
final def withPhase(phaseId: PhaseId): Context = {
192+
if (this.phaseId == phaseId) this
193+
else if (phasedCtx.phaseId == phaseId) phasedCtx
194+
else if (phasedCtxs != null && phasedCtxs(phaseId) != null) phasedCtxs(phaseId)
195+
else {
196+
val ctx1 = fresh.setPhase(phaseId)
197+
if (phasedCtx eq this) phasedCtx = ctx1
198+
else {
199+
if (phasedCtxs == null) phasedCtxs = new Array[Context](base.phases.length)
200+
phasedCtxs(phaseId) = ctx1
201+
}
202+
ctx1
203+
}
204+
}
205+
206+
final def withPhase(phase: Phase): Context =
207+
withPhase(phase.id)
184208
/** If -Ydebug is on, the top of the stack trace where this context
185209
* was created, otherwise `null`.
186210
*/
@@ -266,29 +290,23 @@ object Contexts {
266290
}
267291
*/
268292

269-
/** A fresh clone of this context. */
270-
def fresh: FreshContext = {
271-
val newctx: Context = super.clone.asInstanceOf[FreshContext]
272-
newctx.outer = this
273-
newctx.implicitsCache = null
274-
newctx.setCreationTrace()
275-
// Dotty deviation: Scala2x allows access to private members implicitCache and setCreationTrace
276-
// even from a subclass prefix. Dotty (and Java) do not. It's confirmed as a bug in Scala2x.
277-
newctx.asInstanceOf[FreshContext]
293+
protected def init(outer: Context): this.type = {
294+
this.outer = outer
295+
this.implicitsCache = null
296+
this.phasedCtx = this
297+
this.phasedCtxs = null
298+
setCreationTrace()
299+
this
278300
}
301+
/** A fresh clone of this context. */
302+
def fresh: FreshContext = clone.asInstanceOf[FreshContext].init(this)
303+
304+
final def withOwner(owner: Symbol): Context =
305+
if (owner ne this.owner) fresh.setOwner(owner) else this
279306

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

283-
/**
284-
* This method will always return a phase period equal to phaseId, thus will never return squashed phases
285-
*/
286-
final def withPhase(phaseId: PhaseId): Context =
287-
if (this.phaseId == phaseId) this else fresh.setPhase(phaseId)
288-
final def withPhase(phase: Phase): Context =
289-
if (this.period == phase.period) this else fresh.setPhase(phase)
290-
291-
292310
final def addMode(mode: Mode): Context = withMode(this.mode | mode)
293311
final def maskMode(mode: Mode): Context = withMode(this.mode & mode)
294312
final def retractMode(mode: Mode): Context = withMode(this.mode &~ mode)
@@ -313,15 +331,15 @@ object Contexts {
313331
def setPeriod(period: Period): this.type = { this.period = period; this }
314332
def setMode(mode: Mode): this.type = { this.mode = mode; this }
315333
def setTyperState(typerState: TyperState): this.type = { this.typerState = typerState; this }
316-
def clearTyperState: this.type = setTyperState(typerState.fresh(isCommittable = true))
334+
def setNewTyperState: this.type = setTyperState(typerState.fresh(isCommittable = true))
317335
def setExploreTyperState: this.type = setTyperState(typerState.fresh(isCommittable = false))
318336
def setPrinterFn(printer: Context => Printer): this.type = { this.printerFn = printer; this }
319337
def setOwner(owner: Symbol): this.type = { assert(owner != NoSymbol); this.owner = owner; this }
320338
def setSettings(sstate: SettingsState): this.type = { this.sstate = sstate; this }
321339
def setCompilationUnit(compilationUnit: CompilationUnit): this.type = { this.compilationUnit = compilationUnit; this }
322340
def setTree(tree: Tree[_ >: Untyped]): this.type = { this.tree = tree; this }
323341
def setScope(scope: Scope): this.type = { this.scope = scope; this }
324-
def clearScope: this.type = { this.scope = newScope; this }
342+
def setNewScope: this.type = { this.scope = newScope; this }
325343
def setTypeAssigner(typeAssigner: TypeAssigner): this.type = { this.typeAssigner = typeAssigner; this }
326344
def setTyper(typer: Typer): this.type = { this.scope = typer.scope; setTypeAssigner(typer) }
327345
def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this }

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Symbols._
66
import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer
77
import util.Positions.Position, util.SourcePosition
88
import collection.mutable.ListBuffer
9+
import dotty.tools.dotc.transform.TreeTransforms._
910
import scala.language.implicitConversions
1011

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

134137
implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition =

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ class Definitions {
103103
lazy val Object_!= = newMethod(ObjectClass, nme.NE, methOfAny(BooleanType), Final)
104104
lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final)
105105
lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final)
106-
lazy val Object_isInstanceOf = newT1EmptyParamsMethod(ObjectClass, nme.isInstanceOf_Ob, _ => BooleanType, Final | Synthetic)
107-
lazy val Object_asInstanceOf = newT1EmptyParamsMethod(ObjectClass, nme.asInstanceOf_Ob, PolyParam(_, 0), Final | Synthetic)
106+
lazy val Object_isInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.isInstanceOf_Ob, _ => BooleanType, Final | Synthetic)
107+
lazy val Object_asInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.asInstanceOf_Ob, PolyParam(_, 0), Final | Synthetic)
108108
lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1,
109109
pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final)
110110

@@ -218,6 +218,7 @@ class Definitions {
218218
lazy val OptionClass = ctx.requiredClass("scala.Option")
219219
lazy val BoxedNumberClass = ctx.requiredClass("java.lang.Number")
220220
lazy val ThrowableClass = ctx.requiredClass("java.lang.Throwable")
221+
lazy val ClassCastExceptionClass = ctx.requiredClass("java.lang.ClassCastException")
221222
lazy val JavaSerializableClass = ctx.requiredClass("java.lang.Serializable")
222223
lazy val ComparableClass = ctx.requiredClass("java.lang.Comparable")
223224
lazy val ProductClass = ctx.requiredClass("scala.Product")

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,11 @@ object Phases {
107107
postTyperEmmited = true
108108
new PostTyperTransformer {
109109
override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}")
110-
override protected def transformations: Array[TreeTransform] = transforms.toArray
110+
override def transformations: Array[TreeTransform] = transforms.toArray
111111
}
112112
} else new TreeTransformer {
113113
override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}")
114-
override protected def transformations: Array[TreeTransform] = transforms.toArray
114+
override def transformations: Array[TreeTransform] = transforms.toArray
115115
}
116116
squashedPhases += block
117117
block.init(this, phasess(i).head.id, phasess(i).last.id)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ object SymDenotations {
147147
myFlags |= Touched
148148

149149
// completions.println(s"completing ${this.debugString}")
150-
try completer.complete(this)
150+
try completer.complete(this)(ctx.withPhase(validFor.firstPhaseId))
151151
catch {
152152
case ex: CyclicReference =>
153153
completions.println(s"error while completing ${this.debugString}")

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ import TypeApplications._
3939
/** A decorator that provides methods for modeling type application */
4040
class TypeApplications(val self: Type) extends AnyVal {
4141

42+
def canHaveTypeParams(implicit ctx: Context) = !ctx.erasedTypes || self.isRef(defn.ArrayClass)
43+
4244
/** The type parameters of this type are:
4345
* For a ClassInfo type, the type parameters of its class.
4446
* For a typeref referring to a class, the type parameters of the class.
@@ -128,7 +130,7 @@ class TypeApplications(val self: Type) extends AnyVal {
128130
defn.hkTrait(args map alwaysZero).typeParams
129131
}
130132

131-
if (args.isEmpty) self
133+
if (args.isEmpty || !canHaveTypeParams) self
132134
else self match {
133135
case tp: TypeRef =>
134136
val tsym = tp.symbol
@@ -228,8 +230,11 @@ class TypeApplications(val self: Type) extends AnyVal {
228230
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
229231
*/
230232
def translateParameterized(from: ClassSymbol, to: ClassSymbol)(implicit ctx: Context): Type =
231-
if (self derivesFrom from)
232-
RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info)
233+
if (self.derivesFrom(from))
234+
if (canHaveTypeParams)
235+
RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info)
236+
else
237+
to.typeRef
233238
else self
234239

235240
/** If this is an encoding of a (partially) applied type, return its arguments,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,7 @@ object Types {
10391039
}
10401040
lastDenotation = d
10411041
lastSymbol = d.symbol
1042+
checkedPeriod = ctx.period
10421043
d
10431044
}
10441045

src/dotty/tools/dotc/core/transform/Erasure.scala

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,11 @@ object Erasure {
6161
*/
6262
def transformInfo(sym: Symbol, tp: Type)(implicit ctx: Context): Type = {
6363
val erase = erasureFn(sym is JavaDefined, isSemi = true, sym.isConstructor, wildcardOK = false)
64-
if ((sym eq defn.Object_asInstanceOf) || sym.isType && (sym.owner eq defn.ArrayClass))
65-
sym.info
66-
else if ((sym eq defn.Object_isInstanceOf) || (sym eq defn.ArrayClass.primaryConstructor)) {
67-
val tp @ PolyType(pnames) = sym.info
68-
tp.derivedPolyType(pnames, TypeBounds.empty :: Nil, erase(tp.resultType))
69-
}
70-
else if (sym.isAbstractType)
71-
TypeAlias(WildcardType)
72-
else
73-
erase(tp)
64+
if ((sym eq defn.Object_asInstanceOf) ||
65+
(sym eq defn.Object_isInstanceOf) ||
66+
(sym.owner eq defn.ArrayClass) && (sym.isType || sym.isConstructor)) sym.info
67+
else if (sym.isAbstractType) TypeAlias(WildcardType)
68+
else erase(tp)
7469
}
7570

7671
def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !(
@@ -120,7 +115,7 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard
120115
case tp: TypeRef =>
121116
val sym = tp.symbol
122117
if (!sym.isClass)
123-
if (sym.owner eq defn.ArrayClass) tp else this(tp.info)
118+
if (sym.exists && (sym.owner eq defn.ArrayClass)) tp else this(tp.info) //!!!!
124119
else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tp)
125120
else eraseNormalClassRef(tp)
126121
case tp: RefinedType =>

0 commit comments

Comments
 (0)