summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-02-16 14:42:27 +0100
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2014-02-16 14:42:27 +0100
commit23326def4bf5bcfb7f5286707eed2f57a5da731d (patch)
treefa23894ff7ef13b2da334c8dff008f37c5a37cc3
parent00d19344b0c19a2999e48c6bd9326b94c7b54346 (diff)
parent653c404d7f1307251625a5569d53421d27f248cf (diff)
downloadscala-23326def4bf5bcfb7f5286707eed2f57a5da731d.tar.gz
scala-23326def4bf5bcfb7f5286707eed2f57a5da731d.tar.bz2
scala-23326def4bf5bcfb7f5286707eed2f57a5da731d.zip
Merge pull request #3493 from retronym/ticket/3452-2
SI-3452 Correct Java generic signatures for mixins, static forwarders
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala127
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala274
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala27
-rw-r--r--test/files/neg/t4749.check6
-rw-r--r--test/files/pos/t3452f.scala10
-rw-r--r--test/files/run/mixin-signatures.check59
-rw-r--r--test/files/run/mixin-signatures.scala105
-rw-r--r--test/files/run/t3452.check1
-rw-r--r--test/files/run/t3452.scala21
-rw-r--r--test/files/run/t3452a.check1
-rw-r--r--test/files/run/t3452a/J_2.java5
-rw-r--r--test/files/run/t3452a/S_1.scala24
-rw-r--r--test/files/run/t3452a/S_3.scala5
-rw-r--r--test/files/run/t3452b-bcode.check2
-rw-r--r--test/files/run/t3452b-bcode.flags1
-rw-r--r--test/files/run/t3452b-bcode/J_2.java6
-rw-r--r--test/files/run/t3452b-bcode/S_1.scala17
-rw-r--r--test/files/run/t3452b-bcode/S_3.scala5
-rw-r--r--test/files/run/t3452b.check2
-rw-r--r--test/files/run/t3452b/J_2.java6
-rw-r--r--test/files/run/t3452b/S_1.scala17
-rw-r--r--test/files/run/t3452b/S_3.scala5
-rw-r--r--test/files/run/t3452c.check8
-rw-r--r--test/files/run/t3452c.scala113
-rw-r--r--test/files/run/t3452d/A.scala7
-rw-r--r--test/files/run/t3452d/Test.java12
-rw-r--r--test/files/run/t3452e/A.scala4
-rw-r--r--test/files/run/t3452e/B.java2
-rw-r--r--test/files/run/t3452e/Test.scala3
-rw-r--r--test/files/run/t3452f.scala19
-rw-r--r--test/files/run/t3452g/A.scala9
-rw-r--r--test/files/run/t3452g/Test.java14
-rw-r--r--test/files/run/t3452h.scala8
-rw-r--r--test/files/run/t6554.check1
-rw-r--r--test/files/run/t6554.scala11
-rw-r--r--test/files/run/t7374.check3
-rw-r--r--test/files/run/t7374/Some.scala3
-rw-r--r--test/files/run/t7374/Test.java7
-rw-r--r--test/support/java-tests.txt97
-rw-r--r--tools/compare-java-sigs56
40 files changed, 840 insertions, 263 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 18ccced75e..359e5d6c29 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -583,53 +583,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
trait BCAnnotGen extends BCInnerClassGen {
- /*
- * can-multi-thread
- */
- def ubytesToCharArray(bytes: Array[Byte]): Array[Char] = {
- val ca = new Array[Char](bytes.length)
- var idx = 0
- while (idx < bytes.length) {
- val b: Byte = bytes(idx)
- assert((b & ~0x7f) == 0)
- ca(idx) = b.asInstanceOf[Char]
- idx += 1
- }
-
- ca
- }
-
- /*
- * can-multi-thread
- */
- private def arrEncode(sb: ScalaSigBytes): Array[String] = {
- var strs: List[String] = Nil
- val bSeven: Array[Byte] = sb.sevenBitsMayBeZero
- // chop into slices of at most 65535 bytes, counting 0x00 as taking two bytes (as per JVMS 4.4.7 The CONSTANT_Utf8_info Structure)
- var prevOffset = 0
- var offset = 0
- var encLength = 0
- while (offset < bSeven.size) {
- val deltaEncLength = (if (bSeven(offset) == 0) 2 else 1)
- val newEncLength = encLength.toLong + deltaEncLength
- if (newEncLength >= 65535) {
- val ba = bSeven.slice(prevOffset, offset)
- strs ::= new java.lang.String(ubytesToCharArray(ba))
- encLength = 0
- prevOffset = offset
- } else {
- encLength += deltaEncLength
- offset += 1
- }
- }
- if (prevOffset < offset) {
- assert(offset == bSeven.length)
- val ba = bSeven.slice(prevOffset, offset)
- strs ::= new java.lang.String(ubytesToCharArray(ba))
- }
- assert(strs.size > 1, "encode instead as one String via strEncode()") // TODO too strict?
- mkArrayReverse(strs)
- }
+ import genASM.{ubytesToCharArray, arrEncode}
/*
* can-multi-thread
@@ -676,7 +630,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
av.visit(name, strEncode(sb))
} else {
val arrAnnotV: asm.AnnotationVisitor = av.visitArray(name)
- for(arg <- arrEncode(sb)) { arrAnnotV.visit(name, arg) }
+ for(arg <- genASM.arrEncode(sb)) { arrAnnotV.visit(name, arg) }
arrAnnotV.visitEnd()
} // for the lazy val in ScalaSigBytes to be GC'ed, the invoker of emitAnnotations() should hold the ScalaSigBytes in a method-local var that doesn't escape.
@@ -772,25 +726,6 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
trait BCJGenSigGen {
- // @M don't generate java generics sigs for (members of) implementation
- // classes, as they are monomorphic (TODO: ok?)
- /*
- * must-single-thread
- */
- private def needsGenericSignature(sym: Symbol) = !(
- // PP: This condition used to include sym.hasExpandedName, but this leads
- // to the total loss of generic information if a private member is
- // accessed from a closure: both the field and the accessor were generated
- // without it. This is particularly bad because the availability of
- // generic information could disappear as a consequence of a seemingly
- // unrelated change.
- settings.Ynogenericsig
- || sym.isArtifact
- || sym.isLiftedMethod
- || sym.isBridge
- || (sym.ownerChain exists (_.isImplClass))
- )
-
def getCurrentCUnit(): CompilationUnit
/* @return
@@ -799,61 +734,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
*
* must-single-thread
*/
- def getGenericSignature(sym: Symbol, owner: Symbol): String = {
-
- if (!needsGenericSignature(sym)) { return null }
-
- val memberTpe = enteringErasure(owner.thisType.memberInfo(sym))
-
- val jsOpt: Option[String] = erasure.javaSig(sym, memberTpe)
- if (jsOpt.isEmpty) { return null }
-
- val sig = jsOpt.get
- log(sig) // This seems useful enough in the general case.
-
- def wrap(op: => Unit) = {
- try { op; true }
- catch { case _: Throwable => false }
- }
-
- if (settings.Xverify) {
- // Run the signature parser to catch bogus signatures.
- val isValidSignature = wrap {
- // Alternative: scala.tools.reflect.SigParser (frontend to sun.reflect.generics.parser.SignatureParser)
- import scala.tools.asm.util.CheckClassAdapter
- if (sym.isMethod) { CheckClassAdapter checkMethodSignature sig }
- else if (sym.isTerm) { CheckClassAdapter checkFieldSignature sig }
- else { CheckClassAdapter checkClassSignature sig }
- }
-
- if (!isValidSignature) {
- getCurrentCUnit().warning(sym.pos,
- """|compiler bug: created invalid generic signature for %s in %s
- |signature: %s
- |if this is reproducible, please report bug at https://issues.scala-lang.org/
- """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig))
- return null
- }
- }
-
- if ((settings.check containsName phaseName)) {
- val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe))
- val bytecodeTpe = owner.thisType.memberInfo(sym)
- if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
- getCurrentCUnit().warning(sym.pos,
- """|compiler bug: created generic signature for %s in %s that does not conform to its erasure
- |signature: %s
- |original type: %s
- |normalized type: %s
- |erasure type: %s
- |if this is reproducible, please report bug at http://issues.scala-lang.org/
- """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig, memberTpe, normalizedTpe, bytecodeTpe))
- return null
- }
- }
-
- sig
- }
+ def getGenericSignature(sym: Symbol, owner: Symbol): String = genASM.getGenericSignature(sym, owner, getCurrentCUnit())
} // end of trait BCJGenSigGen
@@ -906,7 +787,7 @@ abstract class BCodeHelpers extends BCodeTypes with BytecodeWriters {
)
// TODO needed? for(ann <- m.annotations) { ann.symbol.initialize }
- val jgensig = if (m.isDeferred) null else getGenericSignature(m, module); // only add generic signature if method concrete; bug #1745
+ val jgensig = genASM.staticForwarderGenericSignature(m, module, getCurrentCUnit())
addRemoteExceptionAnnot(isRemoteClass, hasPublicBitSet(flags), m)
val (throws, others) = m.annotations partition (_.symbol == definitions.ThrowsClass)
val thrownExceptions: List[String] = getExceptions(throws)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
index b03519ce7d..a389816caf 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
@@ -20,7 +20,7 @@ import scala.annotation.tailrec
*
* Documentation at http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/2012Q2/GenASM.pdf
*/
-abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
+abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM { self =>
import global._
import icodes._
import icodes.opcodes._
@@ -803,134 +803,9 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
annot.args.isEmpty &&
!annot.matches(DeprecatedAttr)
- // @M don't generate java generics sigs for (members of) implementation
- // classes, as they are monomorphic (TODO: ok?)
- private def needsGenericSignature(sym: Symbol) = !(
- // PP: This condition used to include sym.hasExpandedName, but this leads
- // to the total loss of generic information if a private member is
- // accessed from a closure: both the field and the accessor were generated
- // without it. This is particularly bad because the availability of
- // generic information could disappear as a consequence of a seemingly
- // unrelated change.
- settings.Ynogenericsig
- || sym.isArtifact
- || sym.isLiftedMethod
- || sym.isBridge
- || (sym.ownerChain exists (_.isImplClass))
- )
-
def getCurrentCUnit(): CompilationUnit
- /** @return
- * - `null` if no Java signature is to be added (`null` is what ASM expects in these cases).
- * - otherwise the signature in question
- */
- def getGenericSignature(sym: Symbol, owner: Symbol): String = {
-
- if (!needsGenericSignature(sym)) { return null }
-
- val memberTpe = enteringErasure(owner.thisType.memberInfo(sym))
-
- val jsOpt: Option[String] = erasure.javaSig(sym, memberTpe)
- if (jsOpt.isEmpty) { return null }
-
- val sig = jsOpt.get
- log(sig) // This seems useful enough in the general case.
-
- def wrap(op: => Unit) = {
- try { op; true }
- catch { case _: Throwable => false }
- }
-
- if (settings.Xverify) {
- // Run the signature parser to catch bogus signatures.
- val isValidSignature = wrap {
- // Alternative: scala.tools.reflect.SigParser (frontend to sun.reflect.generics.parser.SignatureParser)
- import scala.tools.asm.util.CheckClassAdapter
- if (sym.isMethod) { CheckClassAdapter checkMethodSignature sig } // requires asm-util.jar
- else if (sym.isTerm) { CheckClassAdapter checkFieldSignature sig }
- else { CheckClassAdapter checkClassSignature sig }
- }
-
- if(!isValidSignature) {
- getCurrentCUnit().warning(sym.pos,
- """|compiler bug: created invalid generic signature for %s in %s
- |signature: %s
- |if this is reproducible, please report bug at https://issues.scala-lang.org/
- """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig))
- return null
- }
- }
-
- if ((settings.check containsName phaseName)) {
- val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe))
- val bytecodeTpe = owner.thisType.memberInfo(sym)
- if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
- getCurrentCUnit().warning(sym.pos,
- """|compiler bug: created generic signature for %s in %s that does not conform to its erasure
- |signature: %s
- |original type: %s
- |normalized type: %s
- |erasure type: %s
- |if this is reproducible, please report bug at http://issues.scala-lang.org/
- """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig, memberTpe, normalizedTpe, bytecodeTpe))
- return null
- }
- }
-
- sig
- }
-
- def ubytesToCharArray(bytes: Array[Byte]): Array[Char] = {
- val ca = new Array[Char](bytes.length)
- var idx = 0
- while(idx < bytes.length) {
- val b: Byte = bytes(idx)
- assert((b & ~0x7f) == 0)
- ca(idx) = b.asInstanceOf[Char]
- idx += 1
- }
-
- ca
- }
-
- private def arrEncode(sb: ScalaSigBytes): Array[String] = {
- var strs: List[String] = Nil
- val bSeven: Array[Byte] = sb.sevenBitsMayBeZero
- // chop into slices of at most 65535 bytes, counting 0x00 as taking two bytes (as per JVMS 4.4.7 The CONSTANT_Utf8_info Structure)
- var prevOffset = 0
- var offset = 0
- var encLength = 0
- while(offset < bSeven.length) {
- val deltaEncLength = (if(bSeven(offset) == 0) 2 else 1)
- val newEncLength = encLength.toLong + deltaEncLength
- if(newEncLength >= 65535) {
- val ba = bSeven.slice(prevOffset, offset)
- strs ::= new java.lang.String(ubytesToCharArray(ba))
- encLength = 0
- prevOffset = offset
- } else {
- encLength += deltaEncLength
- offset += 1
- }
- }
- if(prevOffset < offset) {
- assert(offset == bSeven.length)
- val ba = bSeven.slice(prevOffset, offset)
- strs ::= new java.lang.String(ubytesToCharArray(ba))
- }
- assert(strs.size > 1, "encode instead as one String via strEncode()") // TODO too strict?
- strs.reverse.toArray
- }
-
- private def strEncode(sb: ScalaSigBytes): String = {
- val ca = ubytesToCharArray(sb.sevenBitsMayBeZero)
- new java.lang.String(ca)
- // debug val bvA = new asm.ByteVector; bvA.putUTF8(s)
- // debug val enc: Array[Byte] = scala.reflect.internal.pickling.ByteCodecs.encode(bytes)
- // debug assert(enc(idx) == bvA.getByte(idx + 2))
- // debug assert(bvA.getLength == enc.size + 2)
- }
+ def getGenericSignature(sym: Symbol, owner: Symbol) = self.getGenericSignature(sym, owner, getCurrentCUnit())
def emitArgument(av: asm.AnnotationVisitor,
name: String,
@@ -1064,7 +939,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
)
// TODO needed? for(ann <- m.annotations) { ann.symbol.initialize }
- val jgensig = if (m.isDeferred) null else getGenericSignature(m, module); // only add generic signature if method concrete; bug #1745
+ val jgensig = staticForwarderGenericSignature(m, module, getCurrentCUnit())
addRemoteExceptionAnnot(isRemoteClass, hasPublicBitSet(flags), m)
val (throws, others) = m.annotations partition (_.symbol == ThrowsClass)
val thrownExceptions: List[String] = getExceptions(throws)
@@ -3303,4 +3178,147 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}
+ // @M don't generate java generics sigs for (members of) implementation
+ // classes, as they are monomorphic (TODO: ok?)
+ private def needsGenericSignature(sym: Symbol) = !(
+ // PP: This condition used to include sym.hasExpandedName, but this leads
+ // to the total loss of generic information if a private member is
+ // accessed from a closure: both the field and the accessor were generated
+ // without it. This is particularly bad because the availability of
+ // generic information could disappear as a consequence of a seemingly
+ // unrelated change.
+ settings.Ynogenericsig
+ || sym.isArtifact
+ || sym.isLiftedMethod
+ || sym.isBridge
+ || (sym.ownerChain exists (_.isImplClass))
+ )
+
+ final def staticForwarderGenericSignature(sym: Symbol, moduleClass: Symbol, unit: CompilationUnit): String = {
+ if (sym.isDeferred) null // only add generic signature if method concrete; bug #1745
+ else {
+ // SI-3452 Static forwarder generation uses the same erased signature as the method if forwards to.
+ // By rights, it should use the signature as-seen-from the module class, and add suitable
+ // primitive and value-class boxing/unboxing.
+ // But for now, just like we did in mixin, we just avoid writing a wrong generic signature
+ // (one that doesn't erase to the actual signature). See run/t3452b for a test case.
+ val memberTpe = enteringErasure(moduleClass.thisType.memberInfo(sym))
+ val erasedMemberType = erasure.erasure(sym)(memberTpe)
+ if (erasedMemberType =:= sym.info)
+ getGenericSignature(sym, moduleClass, memberTpe, unit)
+ else null
+ }
+ }
+
+ /** @return
+ * - `null` if no Java signature is to be added (`null` is what ASM expects in these cases).
+ * - otherwise the signature in question
+ */
+ def getGenericSignature(sym: Symbol, owner: Symbol, unit: CompilationUnit): String = {
+ val memberTpe = enteringErasure(owner.thisType.memberInfo(sym))
+ getGenericSignature(sym, owner, memberTpe, unit)
+ }
+ def getGenericSignature(sym: Symbol, owner: Symbol, memberTpe: Type, unit: CompilationUnit): String = {
+ if (!needsGenericSignature(sym)) { return null }
+
+ val jsOpt: Option[String] = erasure.javaSig(sym, memberTpe)
+ if (jsOpt.isEmpty) { return null }
+
+ val sig = jsOpt.get
+ log(sig) // This seems useful enough in the general case.
+
+ def wrap(op: => Unit) = {
+ try { op; true }
+ catch { case _: Throwable => false }
+ }
+
+ if (settings.Xverify) {
+ // Run the signature parser to catch bogus signatures.
+ val isValidSignature = wrap {
+ // Alternative: scala.tools.reflect.SigParser (frontend to sun.reflect.generics.parser.SignatureParser)
+ import scala.tools.asm.util.CheckClassAdapter
+ if (sym.isMethod) { CheckClassAdapter checkMethodSignature sig } // requires asm-util.jar
+ else if (sym.isTerm) { CheckClassAdapter checkFieldSignature sig }
+ else { CheckClassAdapter checkClassSignature sig }
+ }
+
+ if(!isValidSignature) {
+ unit.warning(sym.pos,
+ """|compiler bug: created invalid generic signature for %s in %s
+ |signature: %s
+ |if this is reproducible, please report bug at https://issues.scala-lang.org/
+ """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig))
+ return null
+ }
+ }
+
+ if ((settings.check containsName phaseName)) {
+ val normalizedTpe = enteringErasure(erasure.prepareSigMap(memberTpe))
+ val bytecodeTpe = owner.thisType.memberInfo(sym)
+ if (!sym.isType && !sym.isConstructor && !(erasure.erasure(sym)(normalizedTpe) =:= bytecodeTpe)) {
+ unit.warning(sym.pos,
+ """|compiler bug: created generic signature for %s in %s that does not conform to its erasure
+ |signature: %s
+ |original type: %s
+ |normalized type: %s
+ |erasure type: %s
+ |if this is reproducible, please report bug at http://issues.scala-lang.org/
+ """.trim.stripMargin.format(sym, sym.owner.skipPackageObject.fullName, sig, memberTpe, normalizedTpe, bytecodeTpe))
+ return null
+ }
+ }
+
+ sig
+ }
+
+ def ubytesToCharArray(bytes: Array[Byte]): Array[Char] = {
+ val ca = new Array[Char](bytes.length)
+ var idx = 0
+ while(idx < bytes.length) {
+ val b: Byte = bytes(idx)
+ assert((b & ~0x7f) == 0)
+ ca(idx) = b.asInstanceOf[Char]
+ idx += 1
+ }
+
+ ca
+ }
+
+ final def arrEncode(sb: ScalaSigBytes): Array[String] = {
+ var strs: List[String] = Nil
+ val bSeven: Array[Byte] = sb.sevenBitsMayBeZero
+ // chop into slices of at most 65535 bytes, counting 0x00 as taking two bytes (as per JVMS 4.4.7 The CONSTANT_Utf8_info Structure)
+ var prevOffset = 0
+ var offset = 0
+ var encLength = 0
+ while(offset < bSeven.length) {
+ val deltaEncLength = (if(bSeven(offset) == 0) 2 else 1)
+ val newEncLength = encLength.toLong + deltaEncLength
+ if(newEncLength >= 65535) {
+ val ba = bSeven.slice(prevOffset, offset)
+ strs ::= new java.lang.String(ubytesToCharArray(ba))
+ encLength = 0
+ prevOffset = offset
+ } else {
+ encLength += deltaEncLength
+ offset += 1
+ }
+ }
+ if(prevOffset < offset) {
+ assert(offset == bSeven.length)
+ val ba = bSeven.slice(prevOffset, offset)
+ strs ::= new java.lang.String(ubytesToCharArray(ba))
+ }
+ assert(strs.size > 1, "encode instead as one String via strEncode()") // TODO too strict?
+ strs.reverse.toArray
+ }
+
+ private def strEncode(sb: ScalaSigBytes): String = {
+ val ca = ubytesToCharArray(sb.sevenBitsMayBeZero)
+ new java.lang.String(ca)
+ // debug val bvA = new asm.ByteVector; bvA.putUTF8(s)
+ // debug val enc: Array[Byte] = scala.reflect.internal.pickling.ByteCodecs.encode(bytes)
+ // debug assert(enc(idx) == bvA.getByte(idx + 2))
+ // debug assert(bvA.getLength == enc.size + 2)
+ }
}
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 89f9cb4b06..673bc04bd9 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -172,18 +172,23 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
// info) as they are seen from the class. We can't use the member that we get from the
// implementation class, as it's a clone that was made after erasure, and thus it does not
// know its info at the beginning of erasure anymore.
- // Optimize: no need if mixinClass has no typeparams.
- mixinMember cloneSymbol clazz modifyInfo (info =>
- if (mixinClass.typeParams.isEmpty) info
- else (clazz.thisType baseType mixinClass) memberInfo mixinMember
- )
+ val sym = mixinMember cloneSymbol clazz
+
+ val erasureMap = erasure.erasure(mixinMember)
+ val erasedInterfaceInfo: Type = erasureMap(mixinMember.info)
+ val specificForwardInfo = (clazz.thisType baseType mixinClass) memberInfo mixinMember
+ val forwarderInfo =
+ if (erasureMap(specificForwardInfo) =:= erasedInterfaceInfo)
+ specificForwardInfo
+ else {
+ erasedInterfaceInfo
+ }
+ // Optimize: no need if mixinClass has no typeparams.
+ // !!! JZ Really? What about the effect of abstract types, prefix?
+ if (mixinClass.typeParams.isEmpty) sym
+ else sym modifyInfo (_ => forwarderInfo)
}
- // clone before erasure got rid of type info we'll need to generate a javaSig
- // now we'll have the type info at (the beginning of) erasure in our history,
- // and now newSym has the info that's been transformed to fit this period
- // (no need for asSeenFrom as phase.erasedTypes)
- // TODO: verify we need the updateInfo and document why
- newSym updateInfo (mixinMember.info cloneInfo newSym)
+ newSym
}
/** Add getters and setters for all non-module fields of an implementation
diff --git a/test/files/neg/t4749.check b/test/files/neg/t4749.check
index 63d5c21532..3539140954 100644
--- a/test/files/neg/t4749.check
+++ b/test/files/neg/t4749.check
@@ -25,6 +25,10 @@ t4749.scala:26: warning: Fail6 has a main method with parameter type Array[Strin
object Fail6 {
^
+t4749.scala:42: warning: Win3 has a main method with parameter type Array[String], but bippy.Win3 will not be a runnable program.
+ Reason: main method must have exact signature (Array[String])Unit
+ object Win3 extends WinBippy[Unit] { }
+ ^
error: No warnings can be incurred under -Xfatal-warnings.
-6 warnings found
+7 warnings found
one error found
diff --git a/test/files/pos/t3452f.scala b/test/files/pos/t3452f.scala
new file mode 100644
index 0000000000..efe25a62fc
--- /dev/null
+++ b/test/files/pos/t3452f.scala
@@ -0,0 +1,10 @@
+class Base[Coll] {
+ trait Transformed[S] {
+ lazy val underlying: Coll = ???
+ }
+}
+
+class Derived extends Base[String] {
+ class C extends Transformed[Any]
+}
+
diff --git a/test/files/run/mixin-signatures.check b/test/files/run/mixin-signatures.check
new file mode 100644
index 0000000000..3031fe75af
--- /dev/null
+++ b/test/files/run/mixin-signatures.check
@@ -0,0 +1,59 @@
+class Test$bar1$ {
+ public java.lang.String Test$bar1$.f(java.lang.Object)
+ public java.lang.Object Test$bar1$.f(java.lang.Object) <bridge> <synthetic>
+ public java.lang.String Test$bar1$.g(java.lang.String)
+ public java.lang.Object Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
+ public java.lang.String Test$bar1$.g(java.lang.Object) <bridge> <synthetic>
+ public java.lang.Object Test$bar1$.h(java.lang.Object)
+}
+
+class Test$bar2$ {
+ public java.lang.Object Test$bar2$.f(java.lang.String)
+ public java.lang.Object Test$bar2$.f(java.lang.Object) <bridge> <synthetic>
+ public java.lang.String Test$bar2$.g(java.lang.String)
+ public java.lang.Object Test$bar2$.g(java.lang.Object) <bridge> <synthetic>
+ public java.lang.Object Test$bar2$.g(java.lang.String) <bridge> <synthetic>
+ public java.lang.Object Test$bar2$.h(java.lang.Object)
+}
+
+class Test$bar3$ {
+ public java.lang.String Foo3.f(java.lang.Object)
+ generic: public java.lang.String Foo3.f(T)
+ public java.lang.Object Foo3.f(java.lang.Object) <bridge> <synthetic>
+ public java.lang.String Test$bar3$.g(java.lang.String)
+ public java.lang.Object Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
+ public java.lang.String Test$bar3$.g(java.lang.Object) <bridge> <synthetic>
+ public java.lang.Object Foo3.h(java.lang.Object)
+}
+
+class Test$bar4$ {
+ public java.lang.Object Foo4.f(java.lang.String)
+ generic: public R Foo4.f(java.lang.String)
+ public java.lang.Object Foo4.f(java.lang.Object) <bridge> <synthetic>
+ public java.lang.String Test$bar4$.g(java.lang.String)
+ public java.lang.Object Test$bar4$.g(java.lang.Object) <bridge> <synthetic>
+ public java.lang.Object Test$bar4$.g(java.lang.String) <bridge> <synthetic>
+ public java.lang.Object Foo4.h(java.lang.Object)
+}
+
+class Test$bar5$ {
+ public java.lang.String Test$bar5$.f(java.lang.String)
+ public java.lang.Object Test$bar5$.f(java.lang.Object) <bridge> <synthetic>
+ public java.lang.Object Test$bar5$.f(java.lang.String) <bridge> <synthetic>
+ public java.lang.String Test$bar5$.f(java.lang.Object) <bridge> <synthetic>
+ public java.lang.String Test$bar5$.g(java.lang.String)
+ public java.lang.Object Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
+ public java.lang.Object Test$bar5$.g(java.lang.String) <bridge> <synthetic>
+ public java.lang.String Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
+ public java.lang.Object Test$bar5$.h(java.lang.Object)
+}
+
+class Foo1$class {
+ public static java.lang.String Foo1$class.f(Foo1,java.lang.Object)
+}
+
+class Foo2$class {
+ public static java.lang.Object Foo2$class.f(Foo2,java.lang.String)
+}
+
+000000000000000000000000000000000000
diff --git a/test/files/run/mixin-signatures.scala b/test/files/run/mixin-signatures.scala
new file mode 100644
index 0000000000..afd3fad877
--- /dev/null
+++ b/test/files/run/mixin-signatures.scala
@@ -0,0 +1,105 @@
+trait Base[T, R] {
+ def f(x: T): R
+ def g(x: T): R
+ def h(x: T): R = null.asInstanceOf[R]
+}
+
+trait Foo1[T] extends Base[T, String] {
+ def f(x: T): String = null
+ def g(x: T): String
+}
+trait Foo2[R] extends Base[String, R] {
+ def f(x: String): R = { print(x.length) ; null.asInstanceOf[R] }
+ def g(x: String): R
+}
+abstract class Foo3[T] extends Base[T, String] {
+ def f(x: T): String = ""
+ def g(x: T): String
+}
+abstract class Foo4[R] extends Base[String, R] {
+ def f(x: String): R = { print(x.length) ; null.asInstanceOf[R] }
+ def g(x: String): R
+}
+
+object Test {
+ object bar1 extends Foo1[String] { def g(x: String): String = { print(x.length) ; "" } }
+ object bar2 extends Foo2[String] { def g(x: String): String = { print(x.length) ; "" } }
+ object bar3 extends Foo3[String] { def g(x: String): String = { print(x.length) ; "" } }
+ object bar4 extends Foo4[String] { def g(x: String): String = { print(x.length) ; "" } }
+
+ // Notice that in bar5, f and g require THREE bridges, because the final
+ // implementation is (String)String, but:
+ //
+ // inherited abstract signatures: T(R), (T)String, and (String)R
+ // which erase to: (Object)Object, (Object)String, and (String)Object
+ //
+ // each of which must be bridged to the actual (String)String implementation.
+ //
+ // public java.lang.String Test$bar5$.g(java.lang.String)
+ // public java.lang.Object Test$bar5$.g(java.lang.String) <bridge> <synthetic>
+ // public java.lang.Object Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
+ // public java.lang.String Test$bar5$.g(java.lang.Object) <bridge> <synthetic>
+ object bar5 extends Foo1[String] with Foo2[String] {
+ override def f(x: String): String = { print(x.length) ; x }
+ def g(x: String): String = { print(x.length) ; x }
+ }
+
+ final def m1[T, R](x: Base[T, R], y: T) = { x.f(y) ; x.g(y) ; x.h(y) }
+ final def m2[T](x: Base[T, String], y: T) = { x.f(y) ; x.g(y) ; x.h(y) }
+ final def m3[R](x: Base[String, R]) = { x.f("") ; x.g("") ; x.h("") }
+ final def m4(x: Base[String, String]) = { x.f("") ; x.g("") ; x.h("") }
+
+ final def m11[T](x: Foo1[T], y: T) = { x.f(y) ; x.g(y) ; x.h(y) }
+ final def m12(x: Foo1[String]) = { x.f("") ; x.g("") ; x.h("") }
+ final def m21[T](x: Foo2[T], y: T) = { x.f("") ; x.g("") ; x.h("") }
+ final def m22(x: Foo2[String]) = { x.f("") ; x.g("") ; x.h("") }
+ final def m31[T](x: Foo3[T], y: T) = { x.f(y) ; x.g(y) ; x.h(y) }
+ final def m32(x: Foo3[String]) = { x.f("") ; x.g("") ; x.h("") }
+ final def m41[T](x: Foo4[T], y: T) = { x.f("") ; x.g("") ; x.h("") }
+ final def m42(x: Foo4[String]) = { x.f("") ; x.g("") ; x.h("") }
+
+ def go = {
+ m1(bar1, "") ; m2(bar1, "") ; m3(bar1) ; m4(bar1)
+ m1(bar2, "") ; m2(bar2, "") ; m3(bar2) ; m4(bar2)
+ m1(bar3, "") ; m2(bar3, "") ; m3(bar3) ; m4(bar3)
+ m1(bar4, "") ; m2(bar4, "") ; m3(bar4) ; m4(bar4)
+
+ m11(bar1, "") ; m12(bar1)
+ m21(bar2, "") ; m22(bar2)
+ m31(bar3, "") ; m32(bar3)
+ m41(bar4, "") ; m42(bar4)
+ ""
+ }
+
+ def flagsString(m: java.lang.reflect.Method) = {
+ val str = List(
+ if (m.isBridge) "<bridge>" else "",
+ if (m.isSynthetic) "<synthetic>" else ""
+ ) filterNot (_ == "") mkString " "
+
+ if (str == "") "" else " " + str
+ //
+ // val flags = scala.reflect.internal.ClassfileConstants.toScalaMethodFlags(m.getModifiers())
+ // scala.tools.nsc.symtab.Flags.flagsToString(flags)
+ }
+
+ def show(clazz: Class[_]) {
+ print(clazz + " {")
+ clazz.getMethods.sortBy(x => (x.getName, x.isBridge, x.toString)) filter (_.getName.length == 1) foreach { m =>
+ print("\n " + m + flagsString(m))
+ if ("" + m != "" + m.toGenericString) {
+ print("\n generic: " + m.toGenericString)
+ }
+ }
+ println("\n}")
+ println("")
+ }
+ def show(x: AnyRef) { show(x.getClass) }
+ def show(x: String) { show(Class.forName(x)) }
+
+ def main(args: Array[String]): Unit = {
+ List(bar1, bar2, bar3, bar4, bar5) foreach show
+ List("Foo1$class", "Foo2$class") foreach show
+ println(go)
+ }
+} \ No newline at end of file
diff --git a/test/files/run/t3452.check b/test/files/run/t3452.check
new file mode 100644
index 0000000000..b8626c4cff
--- /dev/null
+++ b/test/files/run/t3452.check
@@ -0,0 +1 @@
+4
diff --git a/test/files/run/t3452.scala b/test/files/run/t3452.scala
new file mode 100644
index 0000000000..253fc93cfa
--- /dev/null
+++ b/test/files/run/t3452.scala
@@ -0,0 +1,21 @@
+trait IStringPair[T] {
+ def a : String
+ def b : String
+ def build(a : String, b : String) : T
+ def cat(that : IStringPair[T]) = build(this.a + that.a, this.b + that.b)
+ override def toString = a + b
+}
+
+class StringPair(val a : String, val b : String) extends IStringPair[StringPair] {
+ def build(a : String, b : String) = new StringPair(a, b)
+ def len = a.length + b.length
+}
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ val a = new StringPair("A", "B")
+ val b = new StringPair("1", "2")
+ val c = a cat b
+ println(c.len)
+ }
+}
diff --git a/test/files/run/t3452a.check b/test/files/run/t3452a.check
new file mode 100644
index 0000000000..9ff787eb86
--- /dev/null
+++ b/test/files/run/t3452a.check
@@ -0,0 +1 @@
+BulkSearch.searchFor called.
diff --git a/test/files/run/t3452a/J_2.java b/test/files/run/t3452a/J_2.java
new file mode 100644
index 0000000000..62057ffe61
--- /dev/null
+++ b/test/files/run/t3452a/J_2.java
@@ -0,0 +1,5 @@
+public class J_2 {
+ public static void main(String[] args) {
+ BulkSearchInstance.searchFor(new UpRelation());
+ }
+}
diff --git a/test/files/run/t3452a/S_1.scala b/test/files/run/t3452a/S_1.scala
new file mode 100644
index 0000000000..791faf42fa
--- /dev/null
+++ b/test/files/run/t3452a/S_1.scala
@@ -0,0 +1,24 @@
+abstract class BulkSearch {
+ type R <: Row
+ type Rel <: Relation [R]
+ type Corr <: Correspondence[R]
+
+ def searchFor(input: Rel): Mapping[Corr] = { println("BulkSearch.searchFor called.") ; null }
+}
+
+object BulkSearchInstance extends BulkSearch {
+ type R = UpRow
+ type Rel = UpRelation
+ type Corr = UpCorrespondence
+}
+
+class Row
+class UpRow extends Row
+
+class Relation [R <: Row]
+class UpRelation extends Relation [UpRow]
+
+class Correspondence [R <: Row]
+class UpCorrespondence extends Correspondence [UpRow]
+
+class Mapping[MC <: Correspondence[_]]
diff --git a/test/files/run/t3452a/S_3.scala b/test/files/run/t3452a/S_3.scala
new file mode 100644
index 0000000000..aaa898dcde
--- /dev/null
+++ b/test/files/run/t3452a/S_3.scala
@@ -0,0 +1,5 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ J_2.main(args)
+ }
+}
diff --git a/test/files/run/t3452b-bcode.check b/test/files/run/t3452b-bcode.check
new file mode 100644
index 0000000000..204c3d0437
--- /dev/null
+++ b/test/files/run/t3452b-bcode.check
@@ -0,0 +1,2 @@
+Search received: test
+SearchC received: test
diff --git a/test/files/run/t3452b-bcode.flags b/test/files/run/t3452b-bcode.flags
new file mode 100644
index 0000000000..c30091d3de
--- /dev/null
+++ b/test/files/run/t3452b-bcode.flags
@@ -0,0 +1 @@
+-Ybackend:GenBCode
diff --git a/test/files/run/t3452b-bcode/J_2.java b/test/files/run/t3452b-bcode/J_2.java
new file mode 100644
index 0000000000..839f334508
--- /dev/null
+++ b/test/files/run/t3452b-bcode/J_2.java
@@ -0,0 +1,6 @@
+public class J_2 {
+ public static void j() {
+ StringSearch.search("test");
+ StringSearch.searchC("test");
+ }
+}
diff --git a/test/files/run/t3452b-bcode/S_1.scala b/test/files/run/t3452b-bcode/S_1.scala
new file mode 100644
index 0000000000..a209f12035
--- /dev/null
+++ b/test/files/run/t3452b-bcode/S_1.scala
@@ -0,0 +1,17 @@
+trait Search[M] {
+ def search(input: M): C[Int] = {
+ println("Search received: " + input)
+ null
+ }
+}
+
+class SearchC[M] {
+ def searchC(input: M): C[Int] = {
+ println("SearchC received: " + input)
+ null
+ }
+}
+
+object StringSearch extends SearchC[String] with Search[String]
+
+trait C[T]
diff --git a/test/files/run/t3452b-bcode/S_3.scala b/test/files/run/t3452b-bcode/S_3.scala
new file mode 100644
index 0000000000..102b433f47
--- /dev/null
+++ b/test/files/run/t3452b-bcode/S_3.scala
@@ -0,0 +1,5 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ J_2.j()
+ }
+}
diff --git a/test/files/run/t3452b.check b/test/files/run/t3452b.check
new file mode 100644
index 0000000000..204c3d0437
--- /dev/null
+++ b/test/files/run/t3452b.check
@@ -0,0 +1,2 @@
+Search received: test
+SearchC received: test
diff --git a/test/files/run/t3452b/J_2.java b/test/files/run/t3452b/J_2.java
new file mode 100644
index 0000000000..839f334508
--- /dev/null
+++ b/test/files/run/t3452b/J_2.java
@@ -0,0 +1,6 @@
+public class J_2 {
+ public static void j() {
+ StringSearch.search("test");
+ StringSearch.searchC("test");
+ }
+}
diff --git a/test/files/run/t3452b/S_1.scala b/test/files/run/t3452b/S_1.scala
new file mode 100644
index 0000000000..a209f12035
--- /dev/null
+++ b/test/files/run/t3452b/S_1.scala
@@ -0,0 +1,17 @@
+trait Search[M] {
+ def search(input: M): C[Int] = {
+ println("Search received: " + input)
+ null
+ }
+}
+
+class SearchC[M] {
+ def searchC(input: M): C[Int] = {
+ println("SearchC received: " + input)
+ null
+ }
+}
+
+object StringSearch extends SearchC[String] with Search[String]
+
+trait C[T]
diff --git a/test/files/run/t3452b/S_3.scala b/test/files/run/t3452b/S_3.scala
new file mode 100644
index 0000000000..102b433f47
--- /dev/null
+++ b/test/files/run/t3452b/S_3.scala
@@ -0,0 +1,5 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ J_2.j()
+ }
+}
diff --git a/test/files/run/t3452c.check b/test/files/run/t3452c.check
new file mode 100644
index 0000000000..ab47181198
--- /dev/null
+++ b/test/files/run/t3452c.check
@@ -0,0 +1,8 @@
+3
+3
+3
+3
+3
+3
+3
+3
diff --git a/test/files/run/t3452c.scala b/test/files/run/t3452c.scala
new file mode 100644
index 0000000000..2c55767abc
--- /dev/null
+++ b/test/files/run/t3452c.scala
@@ -0,0 +1,113 @@
+trait Base[A, B, C] {
+ def f(x: A, y: B, z: C): Unit
+ def g(x: A, y: B, z: C) = f(x, y, z)
+ def h(x: A, y: B, z: C) = g(x, y, z)
+}
+
+trait D1[B, C] extends Base[String, B, C]
+trait D2[A, B] extends Base[A, B, String]
+trait D3[A, C] extends Base[A, String, C]
+trait D4[A] extends Base[A, String, String]
+trait D5[B] extends Base[String, B, String]
+trait D6[C] extends Base[String, String, C]
+trait D7 extends Base[String, String, String]
+
+trait E1[B, C] extends Base[String, B, C] { def f(x: String, y: B, z: C): Unit ; override def h(x: String, y: B, z: C) = g(x, y, z) }
+trait E2[A, B] extends Base[A, B, String] { def f(x: A, y: B, z: String): Unit ; override def h(x: A, y: B, z: String) = g(x, y, z) }
+trait E3[A, C] extends Base[A, String, C] { def f(x: A, y: String, z: C): Unit ; override def h(x: A, y: String, z: C) = g(x, y, z) }
+trait E4[A] extends Base[A, String, String] { def f(x: A, y: String, z: String): Unit ; override def h(x: A, y: String, z: String) = g(x, y, z) }
+trait E5[B] extends Base[String, B, String] { def f(x: String, y: B, z: String): Unit ; override def h(x: String, y: B, z: String) = g(x, y, z) }
+trait E6[C] extends Base[String, String, C] { def f(x: String, y: String, z: C): Unit ; override def h(x: String, y: String, z: C) = g(x, y, z) }
+trait E7 extends Base[String, String, String] { def f(x: String, y: String, z: String): Unit ; override def h(x: String, y: String, z: String) = g(x, y, z) }
+
+trait F1[B, C] extends Base[String, B, C] { def f(x: String, y: B, z: C): Unit = println(x.length) }
+trait F2[A, B] extends Base[A, B, String] { def f(x: A, y: B, z: String): Unit = println(z.length) }
+trait F3[A, C] extends Base[A, String, C] { def f(x: A, y: String, z: C): Unit = println(y.length) }
+trait F4[A] extends Base[A, String, String] { def f(x: A, y: String, z: String): Unit = println(y.length) }
+trait F5[B] extends Base[String, B, String] { def f(x: String, y: B, z: String): Unit = println(x.length) }
+trait F6[C] extends Base[String, String, C] { def f(x: String, y: String, z: C): Unit = println(x.length) }
+trait F7 extends Base[String, String, String] { def f(x: String, y: String, z: String): Unit = println(x.length) }
+
+abstract class DBag extends D1[String, String] with D2[String, String] with D3[String, String] with D4[String] with D5[String] with D6[String] with D7 {
+ def f(x: String, y: String, z: String) = println(x.length + y.length + z.length)
+}
+abstract class EBag extends E1[String, String] with E2[String, String] with E3[String, String] with E4[String] with E5[String] with E6[String] with E7 {
+ def f(x: String, y: String, z: String) = println(x.length + y.length + z.length)
+}
+abstract class FBag extends F1[String, String] with F2[String, String] with F3[String, String] with F4[String] with F5[String] with F6[String] with F7 {
+ override def f(x: String, y: String, z: String) = println(x.length + y.length + z.length)
+}
+
+abstract class GBag1[A, B] extends Base[A, B, String] with D2[A, B] {
+ def f(x: A, y: B, z: String) = println(z.length)
+}
+abstract class GBag2[A] extends GBag1[A, String] with D4[A] {
+ override def f(x: A, y: String, z: String) = println(z.length)
+}
+abstract class GBag3 extends GBag2[String] with D7 {
+ override def f(x: String, y: String, z: String) = println(z.length)
+}
+class GBag extends GBag3 with D2[String, String] with D3[String, String] with D4[String] with D5[String] with D6[String] with D7 {
+}
+
+object Test {
+ def f0(x: Base[String, String, String]) = x.f("a", "b", "c")
+ def f1(x: D1[String, String]) = x.f("a", "b", "c")
+ def f2(x: D2[String, String]) = x.f("a", "b", "c")
+ def f3(x: D3[String, String]) = x.f("a", "b", "c")
+ def f4(x: D4[String]) = x.f("a", "b", "c")
+ def f5(x: D5[String]) = x.f("a", "b", "c")
+ def f6(x: D6[String]) = x.f("a", "b", "c")
+ def f7(x: D7) = x.f("a", "b", "c")
+
+ def main(args: Array[String]): Unit = {
+ val x = new DBag { }
+ f0(x)
+ f1(x)
+ f2(x)
+ f3(x)
+ f4(x)
+ f5(x)
+ f6(x)
+ f7(x)
+ }
+}
+
+object TestE {
+ def f0(x: Base[String, String, String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f1(x: E1[String, String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f2(x: E2[String, String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f3(x: E3[String, String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f4(x: E4[String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f5(x: E5[String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f6(x: E6[String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f7(x: E7) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+
+ def main(args: Array[String]): Unit = {
+ val x = new EBag { }
+ f0(x)
+ f1(x)
+ f2(x)
+ f3(x)
+ f4(x)
+ f5(x)
+ f6(x)
+ f7(x)
+ }
+}
+
+
+object TestG {
+ def f0(x: Base[String, String, String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f1(x: GBag1[String, String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f2(x: GBag2[String]) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+ def f3(x: GBag3) = { x.f("a", "b", "c") ; x.g("a", "b", "c") ; x.h("a", "b", "c") }
+
+ def main(args: Array[String]): Unit = {
+ val x = new GBag { }
+ f0(x)
+ f1(x)
+ f2(x)
+ f3(x)
+ }
+}
diff --git a/test/files/run/t3452d/A.scala b/test/files/run/t3452d/A.scala
new file mode 100644
index 0000000000..67a2080d27
--- /dev/null
+++ b/test/files/run/t3452d/A.scala
@@ -0,0 +1,7 @@
+trait TraversableLike[A, Repr] {
+ def tail: Repr = null.asInstanceOf[Repr]
+}
+
+abstract class AbstractTrav[A] extends TraversableLike[A, Traversable[A]]
+
+class C[A] extends AbstractTrav[A]
diff --git a/test/files/run/t3452d/Test.java b/test/files/run/t3452d/Test.java
new file mode 100644
index 0000000000..875be6176c
--- /dev/null
+++ b/test/files/run/t3452d/Test.java
@@ -0,0 +1,12 @@
+import scala.collection.immutable.Nil;
+import scala.collection.immutable.List;
+import scala.collection.Traversable;
+
+public class Test {
+ public static void main(String[] args) {
+ C<String> c = new C<String>();
+ // TODO add a bridge during mixin so we can expose
+ // sharper generic signature for `tail`.
+ /*Traversable<String>*/ Object ls = c.tail();
+ }
+}
diff --git a/test/files/run/t3452e/A.scala b/test/files/run/t3452e/A.scala
new file mode 100644
index 0000000000..939172f401
--- /dev/null
+++ b/test/files/run/t3452e/A.scala
@@ -0,0 +1,4 @@
+trait F1[T, R] {
+ def andThen[A](g: R => A): Int = 0
+}
+class C1[TT, RR] extends F1[TT, RR]
diff --git a/test/files/run/t3452e/B.java b/test/files/run/t3452e/B.java
new file mode 100644
index 0000000000..0268af9987
--- /dev/null
+++ b/test/files/run/t3452e/B.java
@@ -0,0 +1,2 @@
+class B extends C1<String, String> {
+}
diff --git a/test/files/run/t3452e/Test.scala b/test/files/run/t3452e/Test.scala
new file mode 100644
index 0000000000..fc175bf94a
--- /dev/null
+++ b/test/files/run/t3452e/Test.scala
@@ -0,0 +1,3 @@
+object Test extends App {
+ new B
+}
diff --git a/test/files/run/t3452f.scala b/test/files/run/t3452f.scala
new file mode 100644
index 0000000000..af64f5c042
--- /dev/null
+++ b/test/files/run/t3452f.scala
@@ -0,0 +1,19 @@
+import language.higherKinds
+
+trait GenSet[A]
+
+trait GenSetTemplate[A, +CC[X] <: GenSet[X]] {
+ def empty: CC[A] = ???
+}
+
+trait SetLike[A, +This <: SetLike[A, This] with Set[A]] {
+ def empty: This
+}
+
+abstract class Set[A] extends GenSet[A] with SetLike[A,Set[A]] with GenSetTemplate[A,Set]
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ locally(classOf[Set[_]]) // trigger classloading to verify class
+ }
+}
diff --git a/test/files/run/t3452g/A.scala b/test/files/run/t3452g/A.scala
new file mode 100644
index 0000000000..a3f74c1e1e
--- /dev/null
+++ b/test/files/run/t3452g/A.scala
@@ -0,0 +1,9 @@
+trait TraversableLike[A, Repr] {
+ def tail: Repr = null.asInstanceOf[Repr]
+}
+
+abstract class AbstractTrav[A] extends TraversableLike[A, AbstractTrav[A]]
+
+object O extends AbstractTrav[String]
+
+class C[A] extends AbstractTrav[A]
diff --git a/test/files/run/t3452g/Test.java b/test/files/run/t3452g/Test.java
new file mode 100644
index 0000000000..c3b4222d16
--- /dev/null
+++ b/test/files/run/t3452g/Test.java
@@ -0,0 +1,14 @@
+
+public class Test {
+ public static void main(String[] args) {
+ // To get better types here, we would need to
+ // add bridge during mixin so we can expose
+ // a generic return type of Traversable<A>, because the erasure
+ // of this (Traversable) differs from the erasure of the mixed
+ // method (erasure(Repr) = Object)
+
+ Object lsSharp = O.tail();
+
+ Object lsSharp2 = new C<String>().tail();
+ }
+}
diff --git a/test/files/run/t3452h.scala b/test/files/run/t3452h.scala
new file mode 100644
index 0000000000..6237d3ea64
--- /dev/null
+++ b/test/files/run/t3452h.scala
@@ -0,0 +1,8 @@
+class Mix___eFoo_I_wBar__f extends Foo_I_ with Bar__f { f; }
+trait T
+abstract class Foo_I_ { class I extends T ; def f: I ; f; }
+trait Bar__f { type I>:Null<:T; def f: I = {null}; f; def gobble: I = {null}}
+
+object Test extends App {
+ new Mix___eFoo_I_wBar__f
+}
diff --git a/test/files/run/t6554.check b/test/files/run/t6554.check
new file mode 100644
index 0000000000..6e0af7b474
--- /dev/null
+++ b/test/files/run/t6554.check
@@ -0,0 +1 @@
+public java.lang.Object Bar.minBy(java.lang.Object) / public java.lang.Object Bar.minBy(java.lang.Object)
diff --git a/test/files/run/t6554.scala b/test/files/run/t6554.scala
new file mode 100644
index 0000000000..5d29d16666
--- /dev/null
+++ b/test/files/run/t6554.scala
@@ -0,0 +1,11 @@
+trait Foo[A] {
+ def minBy[B](b: B): A = ???
+}
+
+class Bar extends Foo[Int]
+
+object Test extends App {
+ val sigs = classOf[Bar].getDeclaredMethods.map(m => s"${m.toString} / ${m.toGenericString}").sorted
+ println(sigs.mkString("\n"))
+}
+// Was public java.lang.Object Bar.minBy(java.lang.Object) / public <B> int Bar.minBy(B)
diff --git a/test/files/run/t7374.check b/test/files/run/t7374.check
new file mode 100644
index 0000000000..4efa6f7af3
--- /dev/null
+++ b/test/files/run/t7374.check
@@ -0,0 +1,3 @@
+List(2, 3)
+ParVector(1, 2, 3)
+List(1, 2)
diff --git a/test/files/run/t7374/Some.scala b/test/files/run/t7374/Some.scala
new file mode 100644
index 0000000000..3266a5642e
--- /dev/null
+++ b/test/files/run/t7374/Some.scala
@@ -0,0 +1,3 @@
+object SomeScala {
+ def list = List(1, 2, 3)
+}
diff --git a/test/files/run/t7374/Test.java b/test/files/run/t7374/Test.java
new file mode 100644
index 0000000000..02f86146ca
--- /dev/null
+++ b/test/files/run/t7374/Test.java
@@ -0,0 +1,7 @@
+public class Test {
+ public static void main(String[] args) {
+ System.out.println(SomeScala.list().tail());
+ System.out.println(SomeScala.list().par());
+ System.out.println(SomeScala.list().init());
+ }
+}
diff --git a/test/support/java-tests.txt b/test/support/java-tests.txt
new file mode 100644
index 0000000000..e0a3fddab3
--- /dev/null
+++ b/test/support/java-tests.txt
@@ -0,0 +1,97 @@
+test/files/buildmanager/t2280
+test/files/buildmanager/t3045
+test/files/buildmanager/t3133
+test/files/jvm/deprecation
+test/files/jvm/t1143-2
+test/files/jvm/t1342
+test/files/jvm/t1464
+test/files/jvm/t2470
+test/files/jvm/t2570
+test/files/jvm/t2585
+test/files/jvm/t3003
+test/files/jvm/t3415
+test/files/jvm/ticket2163
+test/files/jvm/ticket4283
+test/files/jvm/varargs
+test/files/neg/abstract-class-error
+test/files/neg/java-access-neg
+test/files/neg/primitive-sigs-1
+test/files/neg/protected-static-fail
+test/files/neg/t0673
+test/files/neg/t1548
+test/files/neg/t3663
+test/files/neg/t3757
+test/files/neg/t4851
+test/files/pos/chang
+test/files/pos/ilya
+test/files/pos/ilya2
+test/files/pos/java-access-pos
+test/files/pos/javaReadsSigs
+test/files/pos/protected-static
+test/files/pos/raw-map
+test/files/pos/signatures
+test/files/pos/super
+test/files/pos/t0288
+test/files/pos/t0695
+test/files/pos/t1101
+test/files/pos/t1102
+test/files/pos/t1150
+test/files/pos/t1152
+test/files/pos/t1176
+test/files/pos/t1186
+test/files/pos/t1196
+test/files/pos/t1197
+test/files/pos/t1203
+test/files/pos/t1230
+test/files/pos/t1231
+test/files/pos/t1232
+test/files/pos/t1235
+test/files/pos/t1254
+test/files/pos/t1263
+test/files/pos/t1409
+test/files/pos/t1459
+test/files/pos/t1642
+test/files/pos/t1711
+test/files/pos/t1745
+test/files/pos/t1751
+test/files/pos/t1782
+test/files/pos/t1836
+test/files/pos/t1840
+test/files/pos/t1937
+test/files/pos/t2377
+test/files/pos/t2409
+test/files/pos/t2413
+test/files/pos/t2433
+test/files/pos/t2464
+test/files/pos/t2569
+test/files/pos/t2868
+test/files/pos/t294
+test/files/pos/t2940
+test/files/pos/t2956
+test/files/pos/t3249
+test/files/pos/t3349
+test/files/pos/t3404
+test/files/pos/t3429
+test/files/pos/t3486
+test/files/pos/t3521
+test/files/pos/t3567
+test/files/pos/t3622
+test/files/pos/t3642
+test/files/pos/t3938
+test/files/pos/t3946
+test/files/pos/t4402
+test/files/pos/t4603
+test/files/pos/t4737
+test/files/pos/t5644
+test/files/pos/t5703
+test/files/run/inner-parse
+test/files/run/t1430
+test/files/run/t2296a
+test/files/run/t2296b
+test/files/run/t3452a
+test/files/run/t3452b
+test/files/run/t3897
+test/files/run/t4119
+test/files/run/t4238
+test/files/run/t4317
+test/files/run/t4891
diff --git a/tools/compare-java-sigs b/tools/compare-java-sigs
new file mode 100644
index 0000000000..99ab775437
--- /dev/null
+++ b/tools/compare-java-sigs
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# Compare javac -Xprint (i.e. see signatures from java point of view)
+# for the given classes.
+#
+# Sample:
+#
+# % SCALA_HOME=/scala/inst/29 SCALA_BUILD=/scala/inst/3 tools/compare-java-sigs 'scala.Predef$'
+#
+# Comparing javac -Xprint for scala.Predef$ based on '/scala/inst/29' and '/scala/inst/3'
+# 3c3
+# < public final class Predef$ extends scala.LowPriorityImplicits implements scala.ScalaObject {
+# ---
+# > public final class Predef$ extends scala.LowPriorityImplicits {
+# 7d6
+# < private final scala.SpecializableCompanion AnyRef;
+# 21,22d19
+# < public scala.SpecializableCompanion AnyRef();
+# <
+# 68a66,67
+# > public scala.runtime.Nothing$ $qmark$qmark$qmark();
+# >
+# 225c224,226
+# < public scala.collection.immutable.StringOps augmentString(java.lang.String x);
+# ---
+# > public scala.runtime.StringFormat any2stringfmt(java.lang.Object x);
+# >
+# > public java.lang.String augmentString(java.lang.String x);
+# 227c228
+# < public java.lang.String unaugmentString(scala.collection.immutable.StringOps x);
+# ---
+# > public java.lang.String unaugmentString(java.lang.String x);
+#
+
+set -e
+
+[[ $# -gt 0 ]] || {
+ echo "Usage: $(basename $0) <class> <class> ..."
+ echo ""
+ echo "# Example usage"
+ echo "SCALA_HOME=/scala/inst/29 SCALA_BUILD=/scala/inst/3 \\"
+ echo " $(basename $0) scala.Function1 scala.runtime.AbstractFunction1"
+ exit 0
+}
+
+home1=$(cd ${SCALA_HOME:-/scala/inst/3} && pwd)
+home2=$(cd ${SCALA_BUILD:-$(dirname $BASH_SOURCE)/../build/pack} && pwd)
+
+echo "Comparing javac -Xprint for $@ based on '$home1' and '$home2'"
+tmpdir=$(mktemp -dt $(basename $BASH_SOURCE))
+
+cd $tmpdir
+javac -Xprint -cp $home1:$home1/lib/'*' "$@" > before.txt
+javac -Xprint -cp $home2:$home2/lib/'*' "$@" > after.txt
+
+diff before.txt after.txt && echo "No differences in javac -Xprint output."