aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-12-05 14:24:06 +0100
committerMartin Odersky <odersky@gmail.com>2014-12-05 14:36:56 +0100
commit45fd08763fa9f1a45114ce8cd6125e6a83bf3409 (patch)
treedfa5cf37aac42abaffcf7299bfb9da847f9d02cf /src
parent86eb1bb2b5f9ddd9ed8ff45fc304e29c5f6c668d (diff)
downloaddotty-45fd08763fa9f1a45114ce8cd6125e6a83bf3409.tar.gz
dotty-45fd08763fa9f1a45114ce8cd6125e6a83bf3409.tar.bz2
dotty-45fd08763fa9f1a45114ce8cd6125e6a83bf3409.zip
Fix erasure of trait info
After erasure, traits always extend object, and no other class. The change flushed out three more problems, one in the handling of Super trees in erasure, another in bridge method generation. and a third that class RepeatedParam had Seq, which is a trait, as first parent.
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/TypeErasure.scala19
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala2
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala24
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala28
4 files changed, 47 insertions, 26 deletions
diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala
index 7920667e7..3f9149214 100644
--- a/src/dotty/tools/dotc/TypeErasure.scala
+++ b/src/dotty/tools/dotc/TypeErasure.scala
@@ -317,9 +317,19 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
if (cls is Package) tp
else {
def eraseTypeRef(p: TypeRef) = this(p).asInstanceOf[TypeRef]
- val parents: List[TypeRef] =
+ val parents: List[TypeRef] = {
if ((cls eq defn.ObjectClass) || cls.isPrimitiveValueClass) Nil
- else removeLaterObjects(classParents.mapConserve(eraseTypeRef))
+ else {
+ def normalize(trs: List[TypeRef])(implicit ctx: Context): List[TypeRef] = trs match {
+ case tr :: trs1 =>
+ assert(!tr.classSymbol.is(Trait), cls)
+ val tr1 = if (cls is Trait) defn.ObjectClass.typeRef else tr
+ tr1 :: trs1.filterNot(_ isRef defn.ObjectClass)
+ case nil => nil
+ }
+ normalize(classParents.mapConserve(eraseTypeRef))
+ }
+ }
val erasedDecls = decls.filteredScope(d => !d.isType || d.isClass)
tp.derivedClassInfo(NoPrefix, parents, erasedDecls, erasedRef(tp.selfType))
// can't replace selftype by NoType because this would lose the sourceModule link
@@ -376,11 +386,6 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
cls
}
- private def removeLaterObjects(trs: List[TypeRef])(implicit ctx: Context): List[TypeRef] = trs match {
- case tr :: trs1 => tr :: trs1.filterNot(_ isRef defn.ObjectClass)
- case nil => nil
- }
-
/** 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 14baa0b96..895d41516 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -262,7 +262,7 @@ class Definitions {
lazy val ByNameParamClass2x = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, AnyType)
lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, AnyType)
- lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, SeqType)
+ lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, ObjectType, SeqType)
// fundamental classes
lazy val StringClass = ctx.requiredClass("java.lang.String")
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala
index e8a6fd815..b7028430b 100644
--- a/src/dotty/tools/dotc/parsing/Parsers.scala
+++ b/src/dotty/tools/dotc/parsing/Parsers.scala
@@ -1777,23 +1777,23 @@ object Parsers {
}
}
- /** TmplDef ::= ([`case'] `class' | `trait') ClassDef
+ /** TmplDef ::= ([`case'] `class' | `trait') ClassDef
* | [`case'] `object' ObjectDef
*/
def tmplDef(start: Int, mods: Modifiers): Tree = in.token match {
case TRAIT =>
classDef(posMods(start, mods | Trait))
- case CLASS =>
- classDef(posMods(start, mods))
- case CASECLASS =>
- classDef(posMods(start, mods | Case))
- case OBJECT =>
- objectDef(posMods(start, mods | Module))
- case CASEOBJECT =>
- objectDef(posMods(start, mods | Case | Module))
- case _ =>
- syntaxErrorOrIncomplete("expected start of definition")
- EmptyTree
+ case CLASS =>
+ classDef(posMods(start, mods))
+ case CASECLASS =>
+ classDef(posMods(start, mods | Case))
+ case OBJECT =>
+ objectDef(posMods(start, mods | Module))
+ case CASEOBJECT =>
+ objectDef(posMods(start, mods | Case | Module))
+ case _ =>
+ syntaxErrorOrIncomplete("expected start of definition")
+ EmptyTree
}
/** ClassDef ::= Id [ClsTypeParamClause]
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 23f1aada9..2b00cd8af 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -293,6 +293,18 @@ object Erasure extends TypeTestsCasts{
else
assignType(untpd.cpy.Select(tree)(qual, tree.name.primitiveArrayOp), qual)
+ def adaptIfSuper(qual: Tree): Tree = qual match {
+ case Super(thisQual, tpnme.EMPTY) =>
+ val SuperType(thisType, supType) = qual.tpe
+ if (sym.owner is Flags.Trait)
+ cpy.Super(qual)(thisQual, sym.owner.asClass.name)
+ .withType(SuperType(thisType, sym.owner.typeRef))
+ else
+ qual.withType(SuperType(thisType, thisType.firstParent))
+ case _ =>
+ qual
+ }
+
def recur(qual: Tree): Tree = {
val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType
val symIsPrimitive = sym.owner.isPrimitiveValueClass
@@ -306,10 +318,13 @@ object Erasure extends TypeTestsCasts{
recur(unbox(qual, sym.owner.typeRef))
else if (sym.owner eq defn.ArrayClass)
selectArrayMember(qual, erasure(tree.qualifier.typeOpt.widen.finalResultType))
- else if (qual.tpe.derivesFrom(sym.owner) || qual.isInstanceOf[Super])
- select(qual, sym)
- else
- recur(cast(qual, sym.owner.typeRef))
+ else {
+ val qual1 = adaptIfSuper(qual)
+ if (qual1.tpe.derivesFrom(sym.owner) || qual1.isInstanceOf[Super])
+ select(qual1, sym)
+ else
+ recur(cast(qual1, sym.owner.typeRef))
+ }
}
recur(typed(tree.qualifier, AnySelectionProto))
@@ -325,7 +340,7 @@ object Erasure extends TypeTestsCasts{
outer.path(tree.symbol)
}
- private def runtimeCallWithProtoArgs(name: Name, pt: Type, args: Tree*)(implicit ctx: Context): Tree = {
+ private def runtimeCallWithProtoArgs(name: Name, pt: Type, args: Tree*)(implicit ctx: Context): Tree = {
val meth = defn.runtimeMethod(name)
val followingParams = meth.info.firstParamTypes.drop(args.length)
val followingArgs = protoArgs(pt).zipWithConserve(followingParams)(typedExpr).asInstanceOf[List[tpd.Tree]]
@@ -416,7 +431,8 @@ object Erasure extends TypeTestsCasts{
s"${oldSymbol.name(beforeCtx)} bridging with ${newSymbol.name}")
val newOverridden = oldSymbol.denot.allOverriddenSymbols.toSet // TODO: clarify new <-> old in a comment; symbols are swapped here
val oldOverridden = newSymbol.allOverriddenSymbols(beforeCtx).toSet // TODO: can we find a more efficient impl? newOverridden does not have to be a set!
- val neededBridges = oldOverridden -- newOverridden
+ def stillInBaseClass(sym: Symbol) = ctx.owner derivesFrom sym.owner
+ val neededBridges = (oldOverridden -- newOverridden).filter(stillInBaseClass)
var minimalSet = Set[Symbol]()
// compute minimal set of bridges that are needed: