Permalink
Browse files

[nomaster] SI-8114 Binary compat. workaround for erasure bug SI-7120

We can't backport SI-7120 to 2.10.x as it changes erased signatures,
which can lead to interop problems between 2.10.3 and 2.10.4.

But, we can detect one of the nasty symptoms -- a bridge method
with the same signature as its target -- and treat that.

This commit detects duplicate bridges in the ASM (only) backend
and removes them.
  • Loading branch information...
retronym committed Jan 9, 2014
1 parent 1f2cd7e commit 5876e8c62130b4089b146d4fea5bcd926e47bf6f
Showing with 41 additions and 1 deletion.
  1. +26 −1 src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala
  2. +15 −0 test/files/run/t8114.scala
@@ -1397,13 +1397,38 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
}
clasz.fields foreach genField
- clasz.methods foreach { im => genMethod(im, c.symbol.isInterface) }
+ clasz.methods foreach { im =>
+ if (im.symbol.isBridge && isRedundantBridge(im, clasz))
+ // We can't backport the erasure fix of SI-7120 to 2.10.x, but we can detect and delete
+ // bridge methods with identical signatures to their targets.
+ //
+ // NOTE: this backstop only implemented here in the ASM backend, and is not implemented in the FJBG backend.
+ debugwarn(s"Discarding redundant bridge method: ${im.symbol.debugLocationString}. See SI-8114.")
+ else
+ genMethod(im, c.symbol.isInterface)
+ }
addInnerClasses(clasz.symbol, jclass)
jclass.visitEnd()
writeIfNotTooBig("" + c.symbol.name, thisName, jclass, c.symbol)
}
+ private def isRedundantBridge(bridge: IMethod, owner: IClass): Boolean = {
+ def lastCalledMethod: Option[Symbol] = bridge.code.instructions.reverseIterator.collectFirst {
+ case CALL_METHOD(meth, _) => meth
+ }
+ def hasSameSignatureAsBridge(targetMethod: Symbol): Boolean = {
+ val targetIMethod = clasz.methods find (m => m.symbol == targetMethod)
+ // Important to compare the IMethod#paramss, rather then the erased MethodTypes, as
+ // due to the bug SI-7120, these are out of sync. For example, in the `applyOrElse`
+ // method in run/t8114.scala, the method symbol info has a parameter of type `Long`,
+ // but the IMethod parameter has type `Object`. The latter comes from the info of the
+ // symbol representing the parameter ValDef in the tree, which is incorrectly erased.
+ targetIMethod exists (m => bridge.matchesSignature(m))
+ }
+ lastCalledMethod exists hasSameSignatureAsBridge
+ }
+
/**
* @param owner internal name of the enclosing class of the class.
*
View
@@ -0,0 +1,15 @@
+class AbstractTable[T] { type TableElementType }
+class Table[T] extends AbstractTable[T] { type TableElementType = T }
+
+class Query[E, U]
+class TableQuery[E <: AbstractTable[_]] extends Query[E, E#TableElementType]
+
+object Test extends App {
+ object MyTable extends TableQuery[Table[Long]]
+
+ def list[R](q: Query[_, R]): List[R] = Nil
+ list/*[Long]*/(MyTable) collect { case x => x }
+
+ // Generates a redundant bridge method (double definition error)
+ // in 2.10.x due to (at least) the bug in erasure fixed in SI-7120
+}

0 comments on commit 5876e8c

Please sign in to comment.