diff options
author | Martin Odersky <odersky@gmail.com> | 2011-05-11 11:09:08 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2011-05-11 11:09:08 +0000 |
commit | 124cf3f9cbdc582a432c13edd229ba9b8726b99f (patch) | |
tree | 8bc74409a0c080f896a335aa8276f620440285f8 | |
parent | a4d3c77616fffe7ce0b83dcfd929a33aed472773 (diff) | |
download | scala-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.scala | 43 |
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 |