summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2011-05-11 11:09:08 +0000
committerMartin Odersky <odersky@gmail.com>2011-05-11 11:09:08 +0000
commit124cf3f9cbdc582a432c13edd229ba9b8726b99f (patch)
tree8bc74409a0c080f896a335aa8276f620440285f8
parenta4d3c77616fffe7ce0b83dcfd929a33aed472773 (diff)
downloadscala-124cf3f9cbdc582a432c13edd229ba9b8726b99f.tar.gz
scala-124cf3f9cbdc582a432c13edd229ba9b8726b99f.tar.bz2
scala-124cf3f9cbdc582a432c13edd229ba9b8726b99f.zip
Closes #4560. Review by dragos.
-rw-r--r--src/compiler/scala/tools/nsc/transform/CleanUp.scala43
1 files changed, 30 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
index ce76117cfd..41faf00a04 100644
--- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala
+++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala
@@ -27,6 +27,23 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
private val symbolsStoredAsStatic = mutable.Map.empty[String, Symbol]
private def mkTerm(prefix: String): TermName = unit.freshTermName(prefix)
+ /** Kludge to provide a safe fix for #4560:
+ * If we generate a reference in an implementation class, we
+ * watch out for embedded This(..) nodes that point to the interface.
+ * These must be wrong. We fix them by setting symbol and type to
+ * the enclosing implementation class instead.
+ */
+ def safeREF(sym: Symbol) = {
+ def fix(tree: Tree): Tree = tree match {
+ case Select(qual, name) => treeCopy.Select(tree, fix(qual), name)
+ case This(_) if tree.symbol.isInterface && tree.symbol.name + "$class" == currentClass.name.toString =>
+ tree.setSymbol(currentClass).setType(currentClass.tpe)
+ case _ => tree
+ }
+ val tree = REF(sym)
+ if (currentClass.isImplClass) fix(tree) else tree
+ }
+
//private val classConstantMeth = new HashMap[String, Symbol]
//private val symbolStaticFields = new HashMap[String, (Symbol, Tree, Tree)]
@@ -106,7 +123,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val varDef = typedPos( VAL(varSym) === forInit )
newStaticMembers append transform(varDef)
- val varInit = typedPos( REF(varSym) === forInit )
+ val varInit = typedPos( safeREF(varSym) === forInit )
newStaticInits append transform(varInit)
varSym
@@ -149,7 +166,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe) {
case Pair(reflMethodSym, List(forReceiverSym)) =>
- (REF(forReceiverSym) DOT Class_getMethod)(LIT(method), REF(reflParamsCacheSym))
+ (REF(forReceiverSym) DOT Class_getMethod)(LIT(method), safeREF(reflParamsCacheSym))
}
case MONO_CACHE =>
@@ -191,11 +208,11 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
case Pair(reflMethodSym, List(forReceiverSym)) =>
BLOCK(
IF (isCacheEmpty(forReceiverSym)) THEN BLOCK(
- REF(reflMethodCacheSym) === ((REF(forReceiverSym) DOT getMethodSym)(LIT(method), REF(reflParamsCacheSym))) ,
- REF(reflClassCacheSym) === gen.mkSoftRef(REF(forReceiverSym)),
+ safeREF(reflMethodCacheSym) === ((REF(forReceiverSym) DOT getMethodSym)(LIT(method), safeREF(reflParamsCacheSym))) ,
+ safeREF(reflClassCacheSym) === gen.mkSoftRef(REF(forReceiverSym)),
UNIT
) ENDIF,
- REF(reflMethodCacheSym)
+ safeREF(reflMethodCacheSym)
)
}
@@ -227,23 +244,23 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
def mkNewPolyCache = gen.mkSoftRef(NEW(TypeTree(EmptyMethodCacheClass.tpe)))
val reflPolyCacheSym: Symbol = addStaticVariableToClass("reflPoly$Cache", SoftReferenceClass.tpe, mkNewPolyCache, false)
- def getPolyCache = fn(REF(reflPolyCacheSym), nme.get) AS_ATTR MethodCacheClass.tpe
+ def getPolyCache = fn(safeREF(reflPolyCacheSym), nme.get) AS_ATTR MethodCacheClass.tpe
addStaticMethodToClass("reflMethod$Method", List(ClassClass.tpe), MethodClass.tpe)
{ case Pair(reflMethodSym, List(forReceiverSym)) =>
val methodSym = reflMethodSym.newVariable(ad.pos, mkTerm("method")) setInfo MethodClass.tpe
BLOCK(
- IF (getPolyCache OBJ_EQ NULL) THEN (REF(reflPolyCacheSym) === mkNewPolyCache) ENDIF,
+ IF (getPolyCache OBJ_EQ NULL) THEN (safeREF(reflPolyCacheSym) === mkNewPolyCache) ENDIF,
VAL(methodSym) === ((getPolyCache DOT methodCache_find)(REF(forReceiverSym))) ,
IF (REF(methodSym) OBJ_!= NULL) .
THEN (Return(REF(methodSym)))
ELSE {
- def methodSymRHS = ((REF(forReceiverSym) DOT Class_getMethod)(LIT(method), REF(reflParamsCacheSym)))
+ def methodSymRHS = ((REF(forReceiverSym) DOT Class_getMethod)(LIT(method), safeREF(reflParamsCacheSym)))
def cacheRHS = ((getPolyCache DOT methodCache_add)(REF(forReceiverSym), REF(methodSym)))
BLOCK(
REF(methodSym) === (REF(ensureAccessibleMethod) APPLY (methodSymRHS)),
- REF(reflPolyCacheSym) === gen.mkSoftRef(cacheRHS),
+ safeREF(reflPolyCacheSym) === gen.mkSoftRef(cacheRHS),
Return(REF(methodSym))
)
}
@@ -374,7 +391,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
def genDefaultCall = {
// reflective method call machinery
val invokeName = MethodClass.tpe member nme.invoke_ // reflect.Method.invoke(...)
- def cache = REF(reflectiveMethodCache(ad.symbol.name.toString, paramTypes)) // cache Symbol
+ def cache = safeREF(reflectiveMethodCache(ad.symbol.name.toString, paramTypes)) // cache Symbol
def lookup = Apply(cache, List(qual GETCLASS)) // get Method object from cache
def invokeArgs = ArrayValue(TypeTree(ObjectClass.tpe), params) // args for invocation
def invocation = (lookup DOT invokeName)(qual, invokeArgs) // .invoke(qual, ...)
@@ -463,7 +480,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
assert(params.length == mparams.length)
typedPos {
val sym = currentOwner.newValue(ad.pos, mkTerm("qual")) setInfo qual0.tpe
- qual = REF(sym)
+ qual = safeREF(sym)
BLOCK(
VAL(sym) === qual0,
@@ -606,7 +623,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
val staticFieldSym = getSymbolStaticField(symapp.pos, symname, rhs, symapp)
// create a reference to a static field
- val ntree = typedWithPos(symapp.pos)(REF(staticFieldSym))
+ val ntree = typedWithPos(symapp.pos)(safeREF(staticFieldSym))
super.transform(ntree)
@@ -639,7 +656,7 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
// create field definition and initialization
val stfieldDef = theTyper.typed { atPos(pos)(VAL(stfieldSym) === rhs) }
- val stfieldInit = theTyper.typed { atPos(pos)(REF(stfieldSym) === rhs) }
+ val stfieldInit = theTyper.typed { atPos(pos)(safeREF(stfieldSym) === rhs) }
// add field definition to new defs
newStaticMembers append stfieldDef