Skip to content

Commit 5876e8c

Browse files
committed
[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.
1 parent 1f2cd7e commit 5876e8c

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

src/compiler/scala/tools/nsc/backend/jvm/GenASM.scala

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1397,13 +1397,38 @@ abstract class GenASM extends SubComponent with BytecodeWriters with GenJVMASM {
13971397
}
13981398

13991399
clasz.fields foreach genField
1400-
clasz.methods foreach { im => genMethod(im, c.symbol.isInterface) }
1400+
clasz.methods foreach { im =>
1401+
if (im.symbol.isBridge && isRedundantBridge(im, clasz))
1402+
// We can't backport the erasure fix of SI-7120 to 2.10.x, but we can detect and delete
1403+
// bridge methods with identical signatures to their targets.
1404+
//
1405+
// NOTE: this backstop only implemented here in the ASM backend, and is not implemented in the FJBG backend.
1406+
debugwarn(s"Discarding redundant bridge method: ${im.symbol.debugLocationString}. See SI-8114.")
1407+
else
1408+
genMethod(im, c.symbol.isInterface)
1409+
}
14011410

14021411
addInnerClasses(clasz.symbol, jclass)
14031412
jclass.visitEnd()
14041413
writeIfNotTooBig("" + c.symbol.name, thisName, jclass, c.symbol)
14051414
}
14061415

1416+
private def isRedundantBridge(bridge: IMethod, owner: IClass): Boolean = {
1417+
def lastCalledMethod: Option[Symbol] = bridge.code.instructions.reverseIterator.collectFirst {
1418+
case CALL_METHOD(meth, _) => meth
1419+
}
1420+
def hasSameSignatureAsBridge(targetMethod: Symbol): Boolean = {
1421+
val targetIMethod = clasz.methods find (m => m.symbol == targetMethod)
1422+
// Important to compare the IMethod#paramss, rather then the erased MethodTypes, as
1423+
// due to the bug SI-7120, these are out of sync. For example, in the `applyOrElse`
1424+
// method in run/t8114.scala, the method symbol info has a parameter of type `Long`,
1425+
// but the IMethod parameter has type `Object`. The latter comes from the info of the
1426+
// symbol representing the parameter ValDef in the tree, which is incorrectly erased.
1427+
targetIMethod exists (m => bridge.matchesSignature(m))
1428+
}
1429+
lastCalledMethod exists hasSameSignatureAsBridge
1430+
}
1431+
14071432
/**
14081433
* @param owner internal name of the enclosing class of the class.
14091434
*

test/files/run/t8114.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class AbstractTable[T] { type TableElementType }
2+
class Table[T] extends AbstractTable[T] { type TableElementType = T }
3+
4+
class Query[E, U]
5+
class TableQuery[E <: AbstractTable[_]] extends Query[E, E#TableElementType]
6+
7+
object Test extends App {
8+
object MyTable extends TableQuery[Table[Long]]
9+
10+
def list[R](q: Query[_, R]): List[R] = Nil
11+
list/*[Long]*/(MyTable) collect { case x => x }
12+
13+
// Generates a redundant bridge method (double definition error)
14+
// in 2.10.x due to (at least) the bug in erasure fixed in SI-7120
15+
}

0 commit comments

Comments
 (0)