diff options
author | Martin Odersky <odersky@gmail.com> | 2014-12-05 14:24:06 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-12-05 14:36:56 +0100 |
commit | 45fd08763fa9f1a45114ce8cd6125e6a83bf3409 (patch) | |
tree | dfa5cf37aac42abaffcf7299bfb9da847f9d02cf /src | |
parent | 86eb1bb2b5f9ddd9ed8ff45fc304e29c5f6c668d (diff) | |
download | dotty-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.scala | 19 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/parsing/Parsers.scala | 24 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Erasure.scala | 28 |
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: |