diff options
author | Paul Phillips <paulp@improving.org> | 2012-09-29 18:07:09 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-01-30 03:50:25 -0800 |
commit | faca7ec04746ffa8031ae242bac82b2292e93924 (patch) | |
tree | 3885ed589efbfe47ca6389bb0cb357b8e45c8033 /src | |
parent | 09908906862bff6fb6180469d7979abce1bb2bfc (diff) | |
download | scala-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.scala | 32 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 14 |
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 |