aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-08-25 19:13:34 +0200
committerMartin Odersky <odersky@gmail.com>2014-08-25 22:54:06 +0200
commit97d89afc4769c4badb42284c9b5d97b663f870f6 (patch)
treed95868e077a2d701741b64be601fc53585c65493
parent254665e42f2a22ba271c2eb64cb8b1b06a7eaa5c (diff)
downloaddotty-97d89afc4769c4badb42284c9b5d97b663f870f6.tar.gz
dotty-97d89afc4769c4badb42284c9b5d97b663f870f6.tar.bz2
dotty-97d89afc4769c4badb42284c9b5d97b663f870f6.zip
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.
-rw-r--r--src/dotty/tools/dotc/TypeErasure.scala70
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala4
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala2
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala5
-rw-r--r--src/dotty/tools/dotc/core/Types.scala26
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala16
-rw-r--r--test/dotc/tests.scala2
7 files changed, 61 insertions, 64 deletions
diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala
index b65f2889f..c8c54ed03 100644
--- a/src/dotty/tools/dotc/TypeErasure.scala
+++ b/src/dotty/tools/dotc/TypeErasure.scala
@@ -109,6 +109,28 @@ object TypeErasure {
}
loop(tp1.baseClasses, defn.ObjectClass).typeRef
}
+
+ def erasedGlb(tp1: Type, tp2: Type, isJava: Boolean)(implicit ctx: Context): Type = tp1 match {
+ case defn.ArrayType(elem1) =>
+ tp2 match {
+ case defn.ArrayType(elem2) => defn.ArrayType(erasedGlb(elem1, elem2, isJava))
+ case _ => defn.ObjectType
+ }
+ case _ =>
+ tp2 match {
+ case defn.ArrayType(_) => defn.ObjectType
+ case _ =>
+ val tsym1 = tp1.typeSymbol
+ val tsym2 = tp2.typeSymbol
+ if (!tsym2.exists) tp1
+ else if (!tsym1.exists) tp2
+ else if (!isJava && tsym1.derivesFrom(tsym2)) tp1
+ else if (!isJava && tsym2.derivesFrom(tsym1)) tp2
+ else if (tp1.typeSymbol.isRealClass) tp1
+ else if (tp2.typeSymbol.isRealClass) tp2
+ else tp1
+ }
+ }
}
import TypeErasure._
@@ -127,15 +149,15 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
* - otherwise, if T <: Object, scala.Array+[|T|]
* - otherwise, if T is a type paramter coming from Java, scala.Array+[Object].
* - otherwise, Object
- * - For all other type proxies: The erasure of the underlying type.
- * - For a typeref scala.Any, scala.AnyVal, scala.Singleon or scala.NotNull: java.lang.Object.
- * - For a typeref scala.Unit, scala.runtime.BoxedUnit.
- * - For a typeref whose symbol is owned by Array: The typeref itself
- * - For a typeref P.C where C refers to a toplevel class, P.C.
- * - For a typeref P.C where C refers to a nested class, |P|.C.
+ * - For a term ref p.x, the type <noprefix> # x.
+ * - For a typeref scala.Any, scala.AnyVal, scala.Singleon or scala.NotNull: |java.lang.Object|
+ * - For a typeref scala.Unit, |scala.runtime.BoxedUnit|.
+ * - For a typeref whose symbol is owned by Array: The typeref itself, with prefix = <noprefix>
+ * - For a typeref P.C where C refers to a class, <noprefix> # C.
* - For a typeref P.C where C refers to an alias type, the erasure of C's alias.
* - For a typeref P.C where C refers to an abstract type, the erasure of C's upper bound.
- * - For T1 & T2, the merge of |T1| and |T2| (see mergeAnd)
+ * - For all other type proxies: The erasure of the underlying type.
+ * - For T1 & T2, the erased glb of |T1| and |T2| (see erasedGlb)
* - For T1 | T2, the first base class in the linearization of T which is also a base class of T2
* - For => T, ()T
* - For a method type (Fs)scala.Unit, (|Fs|)scala.Unit.
@@ -164,14 +186,12 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
case tp: TermRef =>
assert(tp.symbol.exists, tp)
TermRef(NoPrefix, tp.symbol.asTerm)
- case _: ThisType =>
- tp
case ExprType(rt) =>
MethodType(Nil, Nil, this(rt))
case tp: TypeProxy =>
this(tp.underlying)
case AndType(tp1, tp2) =>
- mergeAnd(this(tp1), this(tp2))
+ erasedGlb(this(tp1), this(tp2), isJava)
case OrType(tp1, tp2) =>
ctx.typeComparer.orType(this(tp1), this(tp2), erased = true)
case tp: MethodType =>
@@ -196,7 +216,8 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
if ((cls eq defn.ObjectClass) || cls.isPrimitiveValueClass) Nil
else if (cls eq defn.ArrayClass) defn.ObjectClass.typeRef :: Nil
else removeLaterObjects(classParents.mapConserve(eraseTypeRef))
- tp.derivedClassInfo(this(pre), parents, decls, this(tp.selfType))
+ tp.derivedClassInfo(NoPrefix, parents, decls, this(tp.selfType))
+ // can't replace selftype by NoType because this would lose the sourceModule link
}
case NoType | NoPrefix | ErrorType =>
tp
@@ -215,9 +236,8 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
unsupported("eraseDerivedValueClass")
private def eraseNormalClassRef(tref: TypeRef)(implicit ctx: Context): Type = {
- val sym = tref.symbol
- if (sym.owner is Package) normalizeClass(sym.asClass).typeRef
- else tref.derivedSelect(this(tref.prefix))
+ val cls = tref.symbol.asClass
+ (if (cls.owner is Package) normalizeClass(cls) else cls).typeRef
}
private def eraseResult(tp: Type)(implicit ctx: Context): Type = tp match {
@@ -247,28 +267,6 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
case nil => nil
}
- private def mergeAnd(tp1: Type, tp2: Type)(implicit ctx: Context): Type = tp1 match {
- case defn.ArrayType(elem1) =>
- tp2 match {
- case defn.ArrayType(elem2) => defn.ArrayType(mergeAnd(elem1, elem2))
- case _ => defn.ObjectType
- }
- case _ =>
- tp2 match {
- case defn.ArrayType(_) => defn.ObjectType
- case _ =>
- val tsym1 = tp1.typeSymbol
- val tsym2 = tp2.typeSymbol
- if (!tsym2.exists) tp1
- else if (!tsym1.exists) tp2
- else if (!isJava && tsym1.derivesFrom(tsym2)) tp1
- else if (!isJava && tsym2.derivesFrom(tsym1)) tp2
- else if (tp1.typeSymbol.isRealClass) tp1
- else if (tp2.typeSymbol.isRealClass) tp2
- else tp1
- }
- }
-
/** The name of the type as it is used in `Signature`s.
* Need to ensure correspondence with erasure!
*/
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 9018d4015..304d9853c 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -377,9 +377,9 @@ class Definitions {
}
object ArrayType {
- def apply(elem: Type) =
+ def apply(elem: Type)(implicit ctx: Context) =
ArrayClass.typeRef.appliedTo(elem :: Nil)
- def unapply(tp: Type) = tp.dealias match {
+ def unapply(tp: Type)(implicit ctx: Context) = tp.dealias match {
case at: RefinedType if (at isRef ArrayClass) && at.argInfos.length == 1 => Some(at.argInfos.head)
case _ => None
}
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 7ba6bbec6..63ce7f756 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -922,7 +922,7 @@ object SymDenotations {
/** The type parameters of this class */
override final def typeParams(implicit ctx: Context): List[TypeSymbol] = {
def computeTypeParams = {
- if (ctx.phase.erasedTypes && (this ne defn.ArrayClass)) Nil
+ if (ctx.phase.erasedTypes && (symbol ne defn.ArrayClass)) Nil
else if (this ne initial) initial.asSymDenotation.typeParams
else decls.filter(sym =>
(sym is TypeParam) && sym.owner == symbol).asInstanceOf[List[TypeSymbol]]
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index 4d818cc6f..29f6dda69 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -11,7 +11,7 @@ import printing.Disambiguation.disambiguated
import util.{Stats, DotClass, SimpleMap}
import config.Config
import config.Printers._
-import TypeErasure.erasedLub
+import TypeErasure.{erasedLub, erasedGlb}
/** Provides methods to compare types.
*/
@@ -1066,12 +1066,13 @@ class TypeComparer(initctx: Context) extends DotClass {
* Such TypeBounds can also be arbitrarily instantiated. In both cases we need to
* make sure that such types do not actually arise in source programs.
*/
- final def andType(tp1: Type, tp2: Type) = ctx.traceIndented(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
+ final def andType(tp1: Type, tp2: Type, erased: Boolean = ctx.erasedTypes) = ctx.traceIndented(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
val t1 = distributeAnd(tp1, tp2)
if (t1.exists) t1
else {
val t2 = distributeAnd(tp2, tp1)
if (t2.exists) t2
+ else if (erased) erasedGlb(tp1, tp2, isJava = false)
else {
//if (isHKRef(tp1)) tp2
//else if (isHKRef(tp2)) tp1
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index a8bfe61e0..e59c28ca2 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -21,7 +21,7 @@ import ast.tpd._
import ast.TreeTypeMap
import printing.Texts._
import ast.untpd
-import transform.Erasure
+import dotty.tools.dotc.transform.Erasure
import printing.Printer
import Hashable._
import Uniques._
@@ -2183,17 +2183,17 @@ object Types {
def selfType(implicit ctx: Context): Type = {
if (selfTypeCache == null) {
def fullRef = fullyAppliedRef(cls.typeRef, cls.typeParams)
- selfTypeCache =
- if (ctx.erasedTypes) fullRef
- else selfInfo match {
- case NoType =>
- fullRef
- case tp: Type =>
- if (cls is Module) tp else AndType(tp, fullRef)
- case self: Symbol =>
- assert(!(cls is Module))
- AndType(self.info, fullRef)
- }
+ def withFullRef(tp: Type): Type =
+ if (ctx.erasedTypes) fullRef else AndType(tp, fullRef)
+ selfTypeCache = selfInfo match {
+ case NoType =>
+ fullRef
+ case tp: Type =>
+ if (cls is Module) tp else withFullRef(tp)
+ case self: Symbol =>
+ assert(!(cls is Module))
+ withFullRef(self.info)
+ }
}
selfTypeCache
}
@@ -2210,7 +2210,7 @@ object Types {
}
def rebase(tp: Type)(implicit ctx: Context): Type =
- if ((prefix eq cls.owner.thisType) || !cls.owner.isClass) tp
+ if ((prefix eq cls.owner.thisType) || !cls.owner.isClass || ctx.erasedTypes) tp
else tp.substThis(cls.owner.asClass, prefix)
private var typeRefCache: Type = null
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 53e253c69..1efc6b53c 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -175,12 +175,13 @@ object Erasure {
* e -> unbox(e, PT) if `PT` is a primitive type and `e` is not of primitive type
* e -> cast(e, PT) otherwise
*/
- def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree = {
- def makeConformant(tpw: Type): Tree = tpw match {
- case MethodType(Nil, _) =>
+ def adaptToType(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
+ if (pt.isInstanceOf[FunProto]) tree
+ else tree.tpe.widen match {
+ case MethodType(Nil, _) if tree.isTerm =>
adaptToType(tree.appliedToNone, pt)
- case _ =>
- if (pt.isInstanceOf[ProtoType])
+ case tpw =>
+ if (pt.isInstanceOf[ProtoType] || tree.tpe <:< pt)
tree
else if (tpw.isErasedValueType)
adaptToType(box(tree), pt)
@@ -193,9 +194,6 @@ object Erasure {
else
cast(tree, pt)
}
- if ((pt.isInstanceOf[FunProto]) || tree.tpe <:< pt) tree
- else makeConformant(tree.tpe.widen)
- }
}
class Typer extends typer.ReTyper with NoChecking {
@@ -254,7 +252,7 @@ object Erasure {
else if (qual.tpe.derivesFrom(sym.owner) || qual.isInstanceOf[Super])
select(qual, sym)
else if (sym.owner eq defn.ArrayClass)
- selectArrayMember(qual, erasure(tree.qualifier.typeOpt.widen))
+ selectArrayMember(qual, erasure(tree.qualifier.typeOpt.widen.finalResultType))
else
recur(cast(qual, sym.owner.typeRef))
}
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 387bab97f..35f85c4d8 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -17,7 +17,7 @@ class tests extends CompilerTest {
"-Ycheck:literalize"
)
- val twice = List("#runs", "2", "-YnoDoubleBindings"/*, "-Ystop-before:terminal"*/)
+ val twice = List("#runs", "2", "-YnoDoubleBindings", "-Ystop-before:terminal")
val doErase = List("-Ystop-before:terminal")
val posDir = "./tests/pos/"