diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala | 21 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala | 20 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Erasure.scala | 45 | ||||
-rw-r--r-- | test/files/run/t8931.check | 1 | ||||
-rw-r--r-- | test/files/run/t8931.scala | 15 |
5 files changed, 54 insertions, 48 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala index 0e2f938602..3b7cbd6392 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala @@ -195,32 +195,13 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { case _ => NoSymbol } - /** - * Drop redundant interfaces (which are implemented by some other parent) from the immediate - * parents. In other words, no two interfaces in the result are related by subtyping. - */ - def dropRedundantInterfaces(lstIfaces: List[Symbol]): List[Symbol] = { - var rest = lstIfaces - var leaves = List.empty[Symbol] - while (!rest.isEmpty) { - val candidate = rest.head - val nonLeaf = leaves exists { lsym => lsym isSubClass candidate } - if (!nonLeaf) { - leaves = candidate :: (leaves filterNot { lsym => candidate isSubClass lsym }) - } - rest = rest.tail - } - - leaves - } - val superInterfaces0: List[Symbol] = classSym.mixinClasses val superInterfaces = existingSymbols(superInterfaces0 ++ classSym.annotations.map(newParentForAnnotation)).distinct assert(!superInterfaces.contains(NoSymbol), s"found NoSymbol among: ${superInterfaces.mkString(", ")}") assert(superInterfaces.forall(s => s.isInterface || s.isTrait), s"found non-interface among: ${superInterfaces.mkString(", ")}") - dropRedundantInterfaces(superInterfaces) + erasure.minimizeInterfaces(superInterfaces.map(_.info)).map(_.typeSymbol) } private def buildNestedInfo(innerClassSym: Symbol): Option[NestedInfo] = { diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala index d0a12c32e5..e56a20c2e7 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala @@ -1214,30 +1214,12 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self => case _ => NoSymbol } - /* Drop redundant interfaces (ones which are implemented by some other parent) from the immediate parents. - * This is important on Android because there is otherwise an interface explosion. - */ - def minimizeInterfaces(lstIfaces: List[Symbol]): List[Symbol] = { - var rest = lstIfaces - var leaves = List.empty[Symbol] - while(!rest.isEmpty) { - val candidate = rest.head - val nonLeaf = leaves exists { lsym => lsym isSubClass candidate } - if(!nonLeaf) { - leaves = candidate :: (leaves filterNot { lsym => candidate isSubClass lsym }) - } - rest = rest.tail - } - - leaves - } - val ps = c.symbol.info.parents val superInterfaces0: List[Symbol] = if(ps.isEmpty) Nil else c.symbol.mixinClasses val superInterfaces = existingSymbols(superInterfaces0 ++ c.symbol.annotations.map(newParentForAttr)).distinct if(superInterfaces.isEmpty) EMPTY_STRING_ARRAY - else mkArray(minimizeInterfaces(superInterfaces) map javaName) + else mkArray(erasure.minimizeInterfaces(superInterfaces.map(_.info)).map(t => javaName(t.typeSymbol))) } var clasz: IClass = _ // this var must be assigned only by genClass() diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 3d8b2f02f3..dc1369bf58 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -185,6 +185,25 @@ abstract class Erasure extends AddInterfaces private def isErasedValueType(tpe: Type) = tpe.isInstanceOf[ErasedValueType] + /* Drop redundant interfaces (ones which are implemented by some other parent) from the immediate parents. + * This is important on Android because there is otherwise an interface explosion. + */ + def minimizeInterfaces(lstIfaces: List[Type]): List[Type] = { + var rest = lstIfaces + var leaves = List.empty[Type] + while(!rest.isEmpty) { + val candidate = rest.head + val nonLeaf = leaves exists { t => t.typeSymbol isSubClass candidate.typeSymbol } + if(!nonLeaf) { + leaves = candidate :: (leaves filterNot { t => candidate.typeSymbol isSubClass t.typeSymbol }) + } + rest = rest.tail + } + + leaves.reverse + } + + /** The Java signature of type 'info', for symbol sym. The symbol is used to give the right return * type for constructors. */ @@ -192,16 +211,24 @@ abstract class Erasure extends AddInterfaces val isTraitSignature = sym0.enclClass.isTrait def superSig(parents: List[Type]) = { - val ps = ( - if (isTraitSignature) { + def isInterfaceOrTrait(sym: Symbol) = sym.isInterface || sym.isTrait + + // a signature should always start with a class + def ensureClassAsFirstParent(tps: List[Type]) = tps match { + case Nil => ObjectTpe :: Nil + case head :: tail if isInterfaceOrTrait(head.typeSymbol) => ObjectTpe :: tps + case _ => tps + } + + val minParents = minimizeInterfaces(parents) + val validParents = + if (isTraitSignature) // java is unthrilled about seeing interfaces inherit from classes - val ok = parents filter (p => p.typeSymbol.isTrait || p.typeSymbol.isInterface) - // traits should always list Object. - if (ok.isEmpty || ok.head.typeSymbol != ObjectClass) ObjectTpe :: ok - else ok - } - else parents - ) + minParents filter (p => isInterfaceOrTrait(p.typeSymbol)) + else minParents + + val ps = ensureClassAsFirstParent(validParents) + (ps map boxedSig).mkString } def boxedSig(tp: Type) = jsig(tp, primitiveOK = false) diff --git a/test/files/run/t8931.check b/test/files/run/t8931.check new file mode 100644 index 0000000000..d08546b5a9 --- /dev/null +++ b/test/files/run/t8931.check @@ -0,0 +1 @@ +List(interface B) diff --git a/test/files/run/t8931.scala b/test/files/run/t8931.scala new file mode 100644 index 0000000000..11718471bc --- /dev/null +++ b/test/files/run/t8931.scala @@ -0,0 +1,15 @@ + +trait A + +trait B extends A + +class C extends A with B + +object Test extends App { + val c = classOf[C] + + println(c.getGenericInterfaces.toList) + + assert(c.getGenericInterfaces.length == c.getInterfaces.length, + s"mismatch between ${c.getGenericInterfaces} and ${c.getInterfaces}") +} |