Skip to content

Commit 97d89af

Browse files
committed
Fixes to erasure
Makes erasure pass the test suite. Erasure is not yet turned turned on by default, because TestNonCyclic fails with a stale symbol error. The problem is that This types are coupled to Symbols and therefore don't reload. This is a problem is This types refer to static symbols that get recompiled. We either have to drop using This types for static references, or redefine thme so that can be reloaded.
1 parent 254665e commit 97d89af

File tree

7 files changed

+61
-64
lines changed

7 files changed

+61
-64
lines changed

src/dotty/tools/dotc/TypeErasure.scala

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,28 @@ object TypeErasure {
109109
}
110110
loop(tp1.baseClasses, defn.ObjectClass).typeRef
111111
}
112+
113+
def erasedGlb(tp1: Type, tp2: Type, isJava: Boolean)(implicit ctx: Context): Type = tp1 match {
114+
case defn.ArrayType(elem1) =>
115+
tp2 match {
116+
case defn.ArrayType(elem2) => defn.ArrayType(erasedGlb(elem1, elem2, isJava))
117+
case _ => defn.ObjectType
118+
}
119+
case _ =>
120+
tp2 match {
121+
case defn.ArrayType(_) => defn.ObjectType
122+
case _ =>
123+
val tsym1 = tp1.typeSymbol
124+
val tsym2 = tp2.typeSymbol
125+
if (!tsym2.exists) tp1
126+
else if (!tsym1.exists) tp2
127+
else if (!isJava && tsym1.derivesFrom(tsym2)) tp1
128+
else if (!isJava && tsym2.derivesFrom(tsym1)) tp2
129+
else if (tp1.typeSymbol.isRealClass) tp1
130+
else if (tp2.typeSymbol.isRealClass) tp2
131+
else tp1
132+
}
133+
}
112134
}
113135
import TypeErasure._
114136

@@ -127,15 +149,15 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
127149
* - otherwise, if T <: Object, scala.Array+[|T|]
128150
* - otherwise, if T is a type paramter coming from Java, scala.Array+[Object].
129151
* - otherwise, Object
130-
* - For all other type proxies: The erasure of the underlying type.
131-
* - For a typeref scala.Any, scala.AnyVal, scala.Singleon or scala.NotNull: java.lang.Object.
132-
* - For a typeref scala.Unit, scala.runtime.BoxedUnit.
133-
* - For a typeref whose symbol is owned by Array: The typeref itself
134-
* - For a typeref P.C where C refers to a toplevel class, P.C.
135-
* - For a typeref P.C where C refers to a nested class, |P|.C.
152+
* - For a term ref p.x, the type <noprefix> # x.
153+
* - For a typeref scala.Any, scala.AnyVal, scala.Singleon or scala.NotNull: |java.lang.Object|
154+
* - For a typeref scala.Unit, |scala.runtime.BoxedUnit|.
155+
* - For a typeref whose symbol is owned by Array: The typeref itself, with prefix = <noprefix>
156+
* - For a typeref P.C where C refers to a class, <noprefix> # C.
136157
* - For a typeref P.C where C refers to an alias type, the erasure of C's alias.
137158
* - For a typeref P.C where C refers to an abstract type, the erasure of C's upper bound.
138-
* - For T1 & T2, the merge of |T1| and |T2| (see mergeAnd)
159+
* - For all other type proxies: The erasure of the underlying type.
160+
* - For T1 & T2, the erased glb of |T1| and |T2| (see erasedGlb)
139161
* - For T1 | T2, the first base class in the linearization of T which is also a base class of T2
140162
* - For => T, ()T
141163
* - For a method type (Fs)scala.Unit, (|Fs|)scala.Unit.
@@ -164,14 +186,12 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
164186
case tp: TermRef =>
165187
assert(tp.symbol.exists, tp)
166188
TermRef(NoPrefix, tp.symbol.asTerm)
167-
case _: ThisType =>
168-
tp
169189
case ExprType(rt) =>
170190
MethodType(Nil, Nil, this(rt))
171191
case tp: TypeProxy =>
172192
this(tp.underlying)
173193
case AndType(tp1, tp2) =>
174-
mergeAnd(this(tp1), this(tp2))
194+
erasedGlb(this(tp1), this(tp2), isJava)
175195
case OrType(tp1, tp2) =>
176196
ctx.typeComparer.orType(this(tp1), this(tp2), erased = true)
177197
case tp: MethodType =>
@@ -196,7 +216,8 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
196216
if ((cls eq defn.ObjectClass) || cls.isPrimitiveValueClass) Nil
197217
else if (cls eq defn.ArrayClass) defn.ObjectClass.typeRef :: Nil
198218
else removeLaterObjects(classParents.mapConserve(eraseTypeRef))
199-
tp.derivedClassInfo(this(pre), parents, decls, this(tp.selfType))
219+
tp.derivedClassInfo(NoPrefix, parents, decls, this(tp.selfType))
220+
// can't replace selftype by NoType because this would lose the sourceModule link
200221
}
201222
case NoType | NoPrefix | ErrorType =>
202223
tp
@@ -215,9 +236,8 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
215236
unsupported("eraseDerivedValueClass")
216237

217238
private def eraseNormalClassRef(tref: TypeRef)(implicit ctx: Context): Type = {
218-
val sym = tref.symbol
219-
if (sym.owner is Package) normalizeClass(sym.asClass).typeRef
220-
else tref.derivedSelect(this(tref.prefix))
239+
val cls = tref.symbol.asClass
240+
(if (cls.owner is Package) normalizeClass(cls) else cls).typeRef
221241
}
222242

223243
private def eraseResult(tp: Type)(implicit ctx: Context): Type = tp match {
@@ -247,28 +267,6 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
247267
case nil => nil
248268
}
249269

250-
private def mergeAnd(tp1: Type, tp2: Type)(implicit ctx: Context): Type = tp1 match {
251-
case defn.ArrayType(elem1) =>
252-
tp2 match {
253-
case defn.ArrayType(elem2) => defn.ArrayType(mergeAnd(elem1, elem2))
254-
case _ => defn.ObjectType
255-
}
256-
case _ =>
257-
tp2 match {
258-
case defn.ArrayType(_) => defn.ObjectType
259-
case _ =>
260-
val tsym1 = tp1.typeSymbol
261-
val tsym2 = tp2.typeSymbol
262-
if (!tsym2.exists) tp1
263-
else if (!tsym1.exists) tp2
264-
else if (!isJava && tsym1.derivesFrom(tsym2)) tp1
265-
else if (!isJava && tsym2.derivesFrom(tsym1)) tp2
266-
else if (tp1.typeSymbol.isRealClass) tp1
267-
else if (tp2.typeSymbol.isRealClass) tp2
268-
else tp1
269-
}
270-
}
271-
272270
/** The name of the type as it is used in `Signature`s.
273271
* Need to ensure correspondence with erasure!
274272
*/

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,9 @@ class Definitions {
377377
}
378378

379379
object ArrayType {
380-
def apply(elem: Type) =
380+
def apply(elem: Type)(implicit ctx: Context) =
381381
ArrayClass.typeRef.appliedTo(elem :: Nil)
382-
def unapply(tp: Type) = tp.dealias match {
382+
def unapply(tp: Type)(implicit ctx: Context) = tp.dealias match {
383383
case at: RefinedType if (at isRef ArrayClass) && at.argInfos.length == 1 => Some(at.argInfos.head)
384384
case _ => None
385385
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ object SymDenotations {
922922
/** The type parameters of this class */
923923
override final def typeParams(implicit ctx: Context): List[TypeSymbol] = {
924924
def computeTypeParams = {
925-
if (ctx.phase.erasedTypes && (this ne defn.ArrayClass)) Nil
925+
if (ctx.phase.erasedTypes && (symbol ne defn.ArrayClass)) Nil
926926
else if (this ne initial) initial.asSymDenotation.typeParams
927927
else decls.filter(sym =>
928928
(sym is TypeParam) && sym.owner == symbol).asInstanceOf[List[TypeSymbol]]

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import printing.Disambiguation.disambiguated
1111
import util.{Stats, DotClass, SimpleMap}
1212
import config.Config
1313
import config.Printers._
14-
import TypeErasure.erasedLub
14+
import TypeErasure.{erasedLub, erasedGlb}
1515

1616
/** Provides methods to compare types.
1717
*/
@@ -1066,12 +1066,13 @@ class TypeComparer(initctx: Context) extends DotClass {
10661066
* Such TypeBounds can also be arbitrarily instantiated. In both cases we need to
10671067
* make sure that such types do not actually arise in source programs.
10681068
*/
1069-
final def andType(tp1: Type, tp2: Type) = ctx.traceIndented(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
1069+
final def andType(tp1: Type, tp2: Type, erased: Boolean = ctx.erasedTypes) = ctx.traceIndented(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
10701070
val t1 = distributeAnd(tp1, tp2)
10711071
if (t1.exists) t1
10721072
else {
10731073
val t2 = distributeAnd(tp2, tp1)
10741074
if (t2.exists) t2
1075+
else if (erased) erasedGlb(tp1, tp2, isJava = false)
10751076
else {
10761077
//if (isHKRef(tp1)) tp2
10771078
//else if (isHKRef(tp2)) tp1

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import ast.tpd._
2121
import ast.TreeTypeMap
2222
import printing.Texts._
2323
import ast.untpd
24-
import transform.Erasure
24+
import dotty.tools.dotc.transform.Erasure
2525
import printing.Printer
2626
import Hashable._
2727
import Uniques._
@@ -2183,17 +2183,17 @@ object Types {
21832183
def selfType(implicit ctx: Context): Type = {
21842184
if (selfTypeCache == null) {
21852185
def fullRef = fullyAppliedRef(cls.typeRef, cls.typeParams)
2186-
selfTypeCache =
2187-
if (ctx.erasedTypes) fullRef
2188-
else selfInfo match {
2189-
case NoType =>
2190-
fullRef
2191-
case tp: Type =>
2192-
if (cls is Module) tp else AndType(tp, fullRef)
2193-
case self: Symbol =>
2194-
assert(!(cls is Module))
2195-
AndType(self.info, fullRef)
2196-
}
2186+
def withFullRef(tp: Type): Type =
2187+
if (ctx.erasedTypes) fullRef else AndType(tp, fullRef)
2188+
selfTypeCache = selfInfo match {
2189+
case NoType =>
2190+
fullRef
2191+
case tp: Type =>
2192+
if (cls is Module) tp else withFullRef(tp)
2193+
case self: Symbol =>
2194+
assert(!(cls is Module))
2195+
withFullRef(self.info)
2196+
}
21972197
}
21982198
selfTypeCache
21992199
}
@@ -2210,7 +2210,7 @@ object Types {
22102210
}
22112211

22122212
def rebase(tp: Type)(implicit ctx: Context): Type =
2213-
if ((prefix eq cls.owner.thisType) || !cls.owner.isClass) tp
2213+
if ((prefix eq cls.owner.thisType) || !cls.owner.isClass || ctx.erasedTypes) tp
22142214
else tp.substThis(cls.owner.asClass, prefix)
22152215

22162216
private var typeRefCache: Type = null

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

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,13 @@ object Erasure {
175175
* e -> unbox(e, PT) if `PT` is a primitive type and `e` is not of primitive type
176176
* e -> cast(e, PT) otherwise
177177
*/
178-
def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
179-
def makeConformant(tpw: Type): Tree = tpw match {
180-
case MethodType(Nil, _) =>
178+
def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
179+
if (pt.isInstanceOf[FunProto]) tree
180+
else tree.tpe.widen match {
181+
case MethodType(Nil, _) if tree.isTerm =>
181182
adaptToType(tree.appliedToNone, pt)
182-
case _ =>
183-
if (pt.isInstanceOf[ProtoType])
183+
case tpw =>
184+
if (pt.isInstanceOf[ProtoType] || tree.tpe <:< pt)
184185
tree
185186
else if (tpw.isErasedValueType)
186187
adaptToType(box(tree), pt)
@@ -193,9 +194,6 @@ object Erasure {
193194
else
194195
cast(tree, pt)
195196
}
196-
if ((pt.isInstanceOf[FunProto]) || tree.tpe <:< pt) tree
197-
else makeConformant(tree.tpe.widen)
198-
}
199197
}
200198

201199
class Typer extends typer.ReTyper with NoChecking {
@@ -254,7 +252,7 @@ object Erasure {
254252
else if (qual.tpe.derivesFrom(sym.owner) || qual.isInstanceOf[Super])
255253
select(qual, sym)
256254
else if (sym.owner eq defn.ArrayClass)
257-
selectArrayMember(qual, erasure(tree.qualifier.typeOpt.widen))
255+
selectArrayMember(qual, erasure(tree.qualifier.typeOpt.widen.finalResultType))
258256
else
259257
recur(cast(qual, sym.owner.typeRef))
260258
}

test/dotc/tests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class tests extends CompilerTest {
1717
"-Ycheck:literalize"
1818
)
1919

20-
val twice = List("#runs", "2", "-YnoDoubleBindings"/*, "-Ystop-before:terminal"*/)
20+
val twice = List("#runs", "2", "-YnoDoubleBindings", "-Ystop-before:terminal")
2121
val doErase = List("-Ystop-before:terminal")
2222

2323
val posDir = "./tests/pos/"

0 commit comments

Comments
 (0)