summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2009-10-28 14:41:00 +0000
committerMartin Odersky <odersky@gmail.com>2009-10-28 14:41:00 +0000
commit0ce248ef65575dce910c82e5714d808851557669 (patch)
tree289a451fe6a621cd4fbc7345f1ec3094c3e819d2 /src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
parentcf53536f9e1b668e9e05c280db84ef2eb502765c (diff)
downloadscala-0ce248ef65575dce910c82e5714d808851557669.tar.gz
scala-0ce248ef65575dce910c82e5714d808851557669.tar.bz2
scala-0ce248ef65575dce910c82e5714d808851557669.zip
Fixed #1342.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/RefChecks.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala75
1 files changed, 72 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index aa3eafc29d..99bf3916a2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -59,6 +59,15 @@ abstract class RefChecks extends InfoTransform {
PolyType(List(), tp)
} else tp
+ val toJavaRepeatedParam = new TypeMap {
+ def apply(tp: Type) = tp match {
+ case TypeRef(pre, RepeatedParamClass, args) =>
+ typeRef(pre, JavaRepeatedParamClass, args)
+ case _ =>
+ mapOver(tp)
+ }
+ }
+
class RefCheckTransformer(unit: CompilationUnit) extends Transformer {
var localTyper: analyzer.Typer = typer;
@@ -91,6 +100,61 @@ abstract class RefChecks extends InfoTransform {
// Override checking ------------------------------------------------------------
+ def hasRepeatedParam(tp: Type): Boolean = tp match {
+ case MethodType(formals, restpe) =>
+ formals.nonEmpty && formals.last.tpe.typeSymbol == RepeatedParamClass ||
+ hasRepeatedParam(restpe)
+ case PolyType(_, restpe) =>
+ hasRepeatedParam(restpe)
+ case _ =>
+ false
+ }
+
+ /** Add bridges for vararg methods that extend Java vararg methods
+ */
+ def addVarargBridges(clazz: Symbol): List[Tree] {
+ val self = clazz.thisType
+
+ val bridges = new ListBuffer[Tree]
+
+ def varargBridge(member: Symbol, bridgetpe: Type): Tree = {
+ val bridge = member.cloneSymbolImpl(clazz)
+ .setPos(clazz.pos).setFlag(member.flags | VBRIDGE)
+ bridge.setInfo(bridgetpe.cloneInfo(bridge))
+ clazz.info.decls enter bridge
+ val List(params) = bridge.paramss
+ val TypeRef(_, JavaRepeatedParamClass, List(elemtp)) = params.last.tpe
+ val (initargs, List(lastarg0)) = (params map Ident) splitAt (params.length - 1)
+ val lastarg = gen.wildcardStar(gen.mkWrapArray(lastarg0, elemtp))
+ val body = Apply(Select(This(clazz), member), initargs ::: List(lastarg))
+ localTyper.typed {
+ /*util.trace("generating varargs bridge")*/(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
+ // 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) {
+ if (!(member hasFlag DEFERRED) && hasRepeatedParam(member.info)) {
+ val jtpe = toJavaRepeatedParam(self.memberType(member))
+ val inherited = clazz.info.nonPrivateMemberAdmitting(member.name, VBRIDGE) filter (
+ sym => (self.memberType(sym) matches jtpe) && !(sym hasFlag VBRIDGE)
+ // 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.exists) {
+ bridges += varargBridge(member, jtpe)
+ }
+ }
+ }
+
+ bridges.toList
+ }
+
/** 1. Check all members of class `clazz' for overriding conditions.
* That is for overriding member M and overridden member O:
*
@@ -325,14 +389,15 @@ abstract class RefChecks extends InfoTransform {
// Bridge symbols qualify.
// Used as a fall back if no overriding symbol of a Java abstract method can be found
def javaErasedOverridingSym(sym: Symbol): Symbol =
- clazz.tpe.findMember(sym.name, PRIVATE, 0, false)(NoSymbol).filter(other =>
+ clazz.tpe.nonPrivateMemberAdmitting(sym.name, BRIDGE).filter(other =>
!other.isDeferred &&
(other hasFlag JAVA) && {
val tp1 = erasure.erasure(clazz.thisType.memberType(sym))
val tp2 = erasure.erasure(clazz.thisType.memberType(other))
atPhase(currentRun.erasurePhase.next)(tp1 matches tp2)
})
- for (member <- clazz.tpe.nonPrivateMembers)
+
+ for (member <- clazz.tpe.nonPrivateMembersAdmitting(VBRIDGE))
if (member.isDeferred && !(clazz hasFlag ABSTRACT) &&
!isAbstractTypeWithoutFBound(member) &&
!((member hasFlag JAVA) && javaErasedOverridingSym(member) != NoSymbol)) {
@@ -346,6 +411,7 @@ abstract class RefChecks extends InfoTransform {
" and overrides incomplete superclass member " + infoString(other)
else ""))
}
+
// 3. Check that concrete classes do not have deferred definitions
// that are not implemented in a subclass.
// Note that this is not the same as (2); In a situation like
@@ -912,11 +978,14 @@ abstract class RefChecks extends InfoTransform {
case ValDef(_, _, _, _) =>
checkDeprecatedOvers()
- case Template(_, _, _) =>
+ case Template(parents, self, body) =>
localTyper = localTyper.atOwner(tree, currentOwner)
validateBaseTypes(currentOwner)
checkDefaultsInOverloaded(currentOwner)
+ val bridges = addVarargBridges(currentOwner)
checkAllOverrides(currentOwner)
+ if (bridges.nonEmpty)
+ result = treeCopy.Template(tree, parents, self, body ::: bridges)
case TypeTree() =>
val existentialParams = new ListBuffer[Symbol]