summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-09-29 18:07:09 -0700
committerPaul Phillips <paulp@improving.org>2013-01-30 03:50:25 -0800
commitfaca7ec04746ffa8031ae242bac82b2292e93924 (patch)
tree3885ed589efbfe47ca6389bb0cb357b8e45c8033 /src
parent09908906862bff6fb6180469d7979abce1bb2bfc (diff)
downloadscala-faca7ec04746ffa8031ae242bac82b2292e93924.tar.gz
scala-faca7ec04746ffa8031ae242bac82b2292e93924.tar.bz2
scala-faca7ec04746ffa8031ae242bac82b2292e93924.zip
SI-4729, overriding java varargs in scala.
[backport] This was a bad interaction between anonymous subclasses and bridge methods. new Foo { override def bar = 5 } Scala figures it can mark "bar" private since hey, what's the difference. The problem is that if it was overriding a java-defined varargs method in scala, the bridge method logic says "Oh, it's private? Then you don't need a varargs bridge." Hey scalac, you're the one that made me private! You made me like this! You! Conflicts: src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala32
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala14
2 files changed, 32 insertions, 14 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 96e480cc84..552dc6b112 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -156,27 +156,22 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// Override checking ------------------------------------------------------------
- def isJavaVarargsAncestor(clazz: Symbol) = (
- clazz.isClass
- && clazz.isJavaDefined
- && (clazz.info.nonPrivateDecls exists isJavaVarArgsMethod)
- )
-
/** Add bridges for vararg methods that extend Java vararg methods
*/
def addVarargBridges(clazz: Symbol): List[Tree] = {
// This is quite expensive, so attempt to skip it completely.
// Insist there at least be a java-defined ancestor which
// defines a varargs method. TODO: Find a cheaper way to exclude.
- if (clazz.thisType.baseClasses exists isJavaVarargsAncestor) {
+ if (inheritsJavaVarArgsMethod(clazz)) {
log("Found java varargs ancestor in " + clazz.fullLocationString + ".")
val self = clazz.thisType
val bridges = new ListBuffer[Tree]
def varargBridge(member: Symbol, bridgetpe: Type): Tree = {
- log("Generating varargs bridge for " + member.fullLocationString + " of type " + bridgetpe)
+ log(s"Generating varargs bridge for ${member.fullLocationString} of type $bridgetpe")
- val bridge = member.cloneSymbolImpl(clazz, member.flags | VBRIDGE) setPos clazz.pos
+ val newFlags = (member.flags | VBRIDGE | ARTIFACT) & ~PRIVATE
+ val bridge = member.cloneSymbolImpl(clazz, newFlags) setPos clazz.pos
bridge.setInfo(bridgetpe.cloneInfo(bridge))
clazz.info.decls enter bridge
@@ -189,26 +184,35 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
localTyper typed DefDef(bridge, body)
}
- // For all concrete non-private members that have a (Scala) repeated parameter:
- // compute the corresponding method type `jtpe` with a Java repeated parameter
+ // For all concrete non-private members (but: see below) that have a (Scala) repeated
+ // parameter: compute the corresponding method type `jtpe` with a Java repeated parameter
// if a method with type `jtpe` exists and that method is not a varargs bridge
// then create a varargs bridge of type `jtpe` that forwards to the
// member method with the Scala vararg type.
- for (member <- clazz.info.nonPrivateMembers) {
+ //
+ // @PP: Can't call nonPrivateMembers because we will miss refinement members,
+ // which have been marked private. See SI-4729.
+ for (member <- nonTrivialMembers(clazz)) {
+ log(s"Considering $member for java varargs bridge in $clazz")
if (!member.isDeferred && member.isMethod && hasRepeatedParam(member.info)) {
val inherited = clazz.info.nonPrivateMemberAdmitting(member.name, VBRIDGE)
+
// Delaying calling memberType as long as possible
if (inherited ne NoSymbol) {
- val jtpe = toJavaRepeatedParam(self.memberType(member))
+ val jtpe = toJavaRepeatedParam(self memberType member)
// this is a bit tortuous: we look for non-private members or bridges
// if we find a bridge everything is OK. If we find another member,
// we need to create a bridge
- if (inherited filter (sym => (self.memberType(sym) matches jtpe) && !(sym hasFlag VBRIDGE)) exists)
+ val inherited1 = inherited filter (sym => !(sym hasFlag VBRIDGE) && (self memberType sym matches jtpe))
+ if (inherited1.exists)
bridges += varargBridge(member, jtpe)
}
}
}
+ if (bridges.size > 0)
+ log(s"Adding ${bridges.size} bridges for methods extending java varargs.")
+
bridges.toList
}
else Nil
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index d0c9b8dd03..6a4730b715 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -7114,6 +7114,14 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
+ def isJavaVarargsAncestor(clazz: Symbol) = (
+ clazz.isClass
+ && clazz.isJavaDefined
+ && (clazz.info.nonPrivateDecls exists isJavaVarArgsMethod)
+ )
+ def inheritsJavaVarArgsMethod(clazz: Symbol) =
+ clazz.thisType.baseClasses exists isJavaVarargsAncestor
+
/** All types in list must be polytypes with type parameter lists of
* same length as tparams.
* Returns list of list of bounds infos, where corresponding type
@@ -7226,6 +7234,12 @@ trait Types extends api.Types { self: SymbolTable =>
else (ps :+ SerializableClass.tpe).toList
)
+ /** Members of the given class, other than those inherited
+ * from Any or AnyRef.
+ */
+ def nonTrivialMembers(clazz: Symbol): Iterable[Symbol] =
+ clazz.info.members filterNot (sym => sym.owner == ObjectClass || sym.owner == AnyClass)
+
def objToAny(tp: Type): Type =
if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyClass.tpe
else tp