Skip to content

Fix erasure of trait info #264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 5, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/dotty/tools/dotc/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,13 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
def eraseTypeRef(p: TypeRef) = this(p).asInstanceOf[TypeRef]
val parents: List[TypeRef] =
if ((cls eq defn.ObjectClass) || cls.isPrimitiveValueClass) Nil
else removeLaterObjects(classParents.mapConserve(eraseTypeRef))
else classParents.mapConserve(eraseTypeRef) 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
}
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
Expand Down Expand Up @@ -376,11 +382,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!
*/
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
24 changes: 12 additions & 12 deletions src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
26 changes: 21 additions & 5 deletions src/dotty/tools/dotc/transform/Erasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))
Expand Down Expand Up @@ -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:
Expand Down