Skip to content

Commit 45fd087

Browse files
committed
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.
1 parent 86eb1bb commit 45fd087

File tree

4 files changed

+47
-26
lines changed

4 files changed

+47
-26
lines changed

src/dotty/tools/dotc/TypeErasure.scala

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,19 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
317317
if (cls is Package) tp
318318
else {
319319
def eraseTypeRef(p: TypeRef) = this(p).asInstanceOf[TypeRef]
320-
val parents: List[TypeRef] =
320+
val parents: List[TypeRef] = {
321321
if ((cls eq defn.ObjectClass) || cls.isPrimitiveValueClass) Nil
322-
else removeLaterObjects(classParents.mapConserve(eraseTypeRef))
322+
else {
323+
def normalize(trs: List[TypeRef])(implicit ctx: Context): List[TypeRef] = trs match {
324+
case tr :: trs1 =>
325+
assert(!tr.classSymbol.is(Trait), cls)
326+
val tr1 = if (cls is Trait) defn.ObjectClass.typeRef else tr
327+
tr1 :: trs1.filterNot(_ isRef defn.ObjectClass)
328+
case nil => nil
329+
}
330+
normalize(classParents.mapConserve(eraseTypeRef))
331+
}
332+
}
323333
val erasedDecls = decls.filteredScope(d => !d.isType || d.isClass)
324334
tp.derivedClassInfo(NoPrefix, parents, erasedDecls, erasedRef(tp.selfType))
325335
// 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
376386
cls
377387
}
378388

379-
private def removeLaterObjects(trs: List[TypeRef])(implicit ctx: Context): List[TypeRef] = trs match {
380-
case tr :: trs1 => tr :: trs1.filterNot(_ isRef defn.ObjectClass)
381-
case nil => nil
382-
}
383-
384389
/** The name of the type as it is used in `Signature`s.
385390
* Need to ensure correspondence with erasure!
386391
*/

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ class Definitions {
262262
lazy val ByNameParamClass2x = specialPolyClass(tpnme.BYNAME_PARAM_CLASS, Covariant, AnyType)
263263
lazy val EqualsPatternClass = specialPolyClass(tpnme.EQUALS_PATTERN, EmptyFlags, AnyType)
264264

265-
lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, SeqType)
265+
lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS, Covariant, ObjectType, SeqType)
266266

267267
// fundamental classes
268268
lazy val StringClass = ctx.requiredClass("java.lang.String")

src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,23 +1777,23 @@ object Parsers {
17771777
}
17781778
}
17791779

1780-
/** TmplDef ::= ([`case'] `class' | `trait') ClassDef
1780+
/** TmplDef ::= ([`case'] `class' | `trait') ClassDef
17811781
* | [`case'] `object' ObjectDef
17821782
*/
17831783
def tmplDef(start: Int, mods: Modifiers): Tree = in.token match {
17841784
case TRAIT =>
17851785
classDef(posMods(start, mods | Trait))
1786-
case CLASS =>
1787-
classDef(posMods(start, mods))
1788-
case CASECLASS =>
1789-
classDef(posMods(start, mods | Case))
1790-
case OBJECT =>
1791-
objectDef(posMods(start, mods | Module))
1792-
case CASEOBJECT =>
1793-
objectDef(posMods(start, mods | Case | Module))
1794-
case _ =>
1795-
syntaxErrorOrIncomplete("expected start of definition")
1796-
EmptyTree
1786+
case CLASS =>
1787+
classDef(posMods(start, mods))
1788+
case CASECLASS =>
1789+
classDef(posMods(start, mods | Case))
1790+
case OBJECT =>
1791+
objectDef(posMods(start, mods | Module))
1792+
case CASEOBJECT =>
1793+
objectDef(posMods(start, mods | Case | Module))
1794+
case _ =>
1795+
syntaxErrorOrIncomplete("expected start of definition")
1796+
EmptyTree
17971797
}
17981798

17991799
/** ClassDef ::= Id [ClsTypeParamClause]

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,18 @@ object Erasure extends TypeTestsCasts{
293293
else
294294
assignType(untpd.cpy.Select(tree)(qual, tree.name.primitiveArrayOp), qual)
295295

296+
def adaptIfSuper(qual: Tree): Tree = qual match {
297+
case Super(thisQual, tpnme.EMPTY) =>
298+
val SuperType(thisType, supType) = qual.tpe
299+
if (sym.owner is Flags.Trait)
300+
cpy.Super(qual)(thisQual, sym.owner.asClass.name)
301+
.withType(SuperType(thisType, sym.owner.typeRef))
302+
else
303+
qual.withType(SuperType(thisType, thisType.firstParent))
304+
case _ =>
305+
qual
306+
}
307+
296308
def recur(qual: Tree): Tree = {
297309
val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType
298310
val symIsPrimitive = sym.owner.isPrimitiveValueClass
@@ -306,10 +318,13 @@ object Erasure extends TypeTestsCasts{
306318
recur(unbox(qual, sym.owner.typeRef))
307319
else if (sym.owner eq defn.ArrayClass)
308320
selectArrayMember(qual, erasure(tree.qualifier.typeOpt.widen.finalResultType))
309-
else if (qual.tpe.derivesFrom(sym.owner) || qual.isInstanceOf[Super])
310-
select(qual, sym)
311-
else
312-
recur(cast(qual, sym.owner.typeRef))
321+
else {
322+
val qual1 = adaptIfSuper(qual)
323+
if (qual1.tpe.derivesFrom(sym.owner) || qual1.isInstanceOf[Super])
324+
select(qual1, sym)
325+
else
326+
recur(cast(qual1, sym.owner.typeRef))
327+
}
313328
}
314329

315330
recur(typed(tree.qualifier, AnySelectionProto))
@@ -325,7 +340,7 @@ object Erasure extends TypeTestsCasts{
325340
outer.path(tree.symbol)
326341
}
327342

328-
private def runtimeCallWithProtoArgs(name: Name, pt: Type, args: Tree*)(implicit ctx: Context): Tree = {
343+
private def runtimeCallWithProtoArgs(name: Name, pt: Type, args: Tree*)(implicit ctx: Context): Tree = {
329344
val meth = defn.runtimeMethod(name)
330345
val followingParams = meth.info.firstParamTypes.drop(args.length)
331346
val followingArgs = protoArgs(pt).zipWithConserve(followingParams)(typedExpr).asInstanceOf[List[tpd.Tree]]
@@ -416,7 +431,8 @@ object Erasure extends TypeTestsCasts{
416431
s"${oldSymbol.name(beforeCtx)} bridging with ${newSymbol.name}")
417432
val newOverridden = oldSymbol.denot.allOverriddenSymbols.toSet // TODO: clarify new <-> old in a comment; symbols are swapped here
418433
val oldOverridden = newSymbol.allOverriddenSymbols(beforeCtx).toSet // TODO: can we find a more efficient impl? newOverridden does not have to be a set!
419-
val neededBridges = oldOverridden -- newOverridden
434+
def stillInBaseClass(sym: Symbol) = ctx.owner derivesFrom sym.owner
435+
val neededBridges = (oldOverridden -- newOverridden).filter(stillInBaseClass)
420436

421437
var minimalSet = Set[Symbol]()
422438
// compute minimal set of bridges that are needed:

0 commit comments

Comments
 (0)