diff options
author | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2014-02-16 14:42:27 +0100 |
---|---|---|
committer | Grzegorz Kossakowski <grzegorz.kossakowski@gmail.com> | 2014-02-16 14:42:27 +0100 |
commit | 23326def4bf5bcfb7f5286707eed2f57a5da731d (patch) | |
tree | fa23894ff7ef13b2da334c8dff008f37c5a37cc3 | |
parent | 00d19344b0c19a2999e48c6bd9326b94c7b54346 (diff) | |
parent | 653c404d7f1307251625a5569d53421d27f248cf (diff) | |
download | scala-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
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." |