summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2017-01-12 14:46:30 -0800
committerAdriaan Moors <adriaan@lightbend.com>2017-01-24 16:35:55 -0800
commita75d3fdda25f228779ba7a6345571e6fce941197 (patch)
treec6c71e0070dc6dd11c44ac0a4136ceccbbe198ec /src
parentdc7ff5dd8402ea9cc1109bf729035b82c1340a51 (diff)
downloadscala-a75d3fdda25f228779ba7a6345571e6fce941197.tar.gz
scala-a75d3fdda25f228779ba7a6345571e6fce941197.tar.bz2
scala-a75d3fdda25f228779ba7a6345571e6fce941197.zip
SI-1459 two bridges for impl of java generic vararg method
A Scala method that implements a generic, Java-defined varargs method, needs two bridges: - to convert the collections for the repeated parameters (VBRIDGE) - to bridge the generics gap (BRIDGE) Refchecks emits the varargs "bridges", and erasure takes care of the other gap. Because a VBRIDGE was also an ARTIFACT, it was wrongly considered inert with respect to erasure, because `OverridingPairs` by default excluded artifacts. Removed the artifact flag from those VBRIDGES, so that they qualify for a real bridge. It would also work to include VBRIDGE methods that are artifacts in BridgesCursor.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Erasure.scala38
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Flags.scala2
3 files changed, 23 insertions, 19 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala
index 7a06c0cf2c..6b987f0089 100644
--- a/src/compiler/scala/tools/nsc/transform/Erasure.scala
+++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -411,7 +411,15 @@ abstract class Erasure extends AddInterfaces
override def newTyper(context: Context) = new Eraser(context)
class ComputeBridges(unit: CompilationUnit, root: Symbol) {
- assert(phase == currentRun.erasurePhase, phase)
+
+ class BridgesCursor(root: Symbol) extends overridingPairs.Cursor(root) {
+ override def parents = List(root.info.firstParent)
+ // Varargs bridges may need generic bridges due to the non-repeated part of the signature of the involved methods.
+ // The vararg bridge is generated during refchecks (probably to simplify override checking),
+ // but then the resulting varargs "bridge" method may itself need an actual erasure bridge.
+ // TODO: like javac, generate just one bridge method that wraps Seq <-> varargs and does erasure-induced casts
+ override def exclude(sym: Symbol) = !sym.isMethod || super.exclude(sym)
+ }
var toBeRemoved = immutable.Set[Symbol]()
val site = root.thisType
@@ -419,12 +427,7 @@ abstract class Erasure extends AddInterfaces
val bridgeTarget = mutable.HashMap[Symbol, Symbol]()
var bridges = List[Tree]()
- val opc = enteringExplicitOuter {
- new overridingPairs.Cursor(root) {
- override def parents = List(root.info.firstParent)
- override def exclude(sym: Symbol) = !sym.isMethod || super.exclude(sym)
- }
- }
+ val opc = enteringExplicitOuter { new BridgesCursor(root) }
def compute(): (List[Tree], immutable.Set[Symbol]) = {
while (opc.hasNext) {
@@ -811,6 +814,16 @@ abstract class Erasure extends AddInterfaces
}
}
+ private class DoubleDefsCursor(root: Symbol) extends Cursor(root) {
+ // specialized members have no type history before 'specialize', causing double def errors for curried defs
+ override def exclude(sym: Symbol): Boolean = (
+ sym.isType
+ || super.exclude(sym)
+ || !sym.hasTypeAt(currentRun.refchecksPhase.id)
+ )
+ override def matches(lo: Symbol, high: Symbol) = !high.isPrivate
+ }
+
/** Emit an error if there is a double definition. This can happen if:
*
* - A template defines two members with the same name and erased type.
@@ -821,21 +834,12 @@ abstract class Erasure extends AddInterfaces
*/
private def checkNoDoubleDefs(root: Symbol) {
checkNoDeclaredDoubleDefs(root)
- object opc extends Cursor(root) {
- // specialized members have no type history before 'specialize', causing double def errors for curried defs
- override def exclude(sym: Symbol): Boolean = (
- sym.isType
- || super.exclude(sym)
- || !sym.hasTypeAt(currentRun.refchecksPhase.id)
- )
- override def matches(lo: Symbol, high: Symbol) = !high.isPrivate
- }
def isErasureDoubleDef(pair: SymbolPair) = {
import pair._
log(s"Considering for erasure clash:\n$pair")
!exitingRefchecks(lowType matches highType) && sameTypeAfterErasure(low, high)
}
- opc.iterator filter isErasureDoubleDef foreach doubleDefError
+ (new DoubleDefsCursor(root)).iterator filter isErasureDoubleDef foreach doubleDefError
}
/** Add bridge definitions to a template. This means:
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 3b2e07bdbd..0b44566108 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -193,7 +193,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
def varargBridge(member: Symbol, bridgetpe: Type): Tree = {
log(s"Generating varargs bridge for ${member.fullLocationString} of type $bridgetpe")
- val newFlags = (member.flags | VBRIDGE | ARTIFACT) & ~PRIVATE
+ val newFlags = (member.flags | VBRIDGE) & ~PRIVATE
val bridge = member.cloneSymbolImpl(clazz, newFlags) setPos clazz.pos
bridge.setInfo(bridgetpe.cloneInfo(bridge))
clazz.info.decls enter bridge
diff --git a/src/reflect/scala/reflect/internal/Flags.scala b/src/reflect/scala/reflect/internal/Flags.scala
index 754b96a9dd..64273f005f 100644
--- a/src/reflect/scala/reflect/internal/Flags.scala
+++ b/src/reflect/scala/reflect/internal/Flags.scala
@@ -164,7 +164,7 @@ class Flags extends ModifierFlags {
final val LOCKED = 1L << 39 // temporary flag to catch cyclic dependencies
final val SPECIALIZED = 1L << 40 // symbol is a generated specialized member
- final val VBRIDGE = 1L << 42 // symbol is a varargs bridge
+ final val VBRIDGE = 1L << 42 // symbol is a varargs bridge (but not a bridge at the bytecode level)
final val VARARGS = 1L << 43 // symbol is a Java-style varargs method
final val TRIEDCOOKING = 1L << 44 // `Cooking` has been tried on this symbol