Fix various InnerClasses bugs.

This commit fixes two major problems:

  1. InnerClasses table missed entries
     that would close the chain between
     nested and top-level class.
     
  2. In some situations, classes
     corresponding to objects would be
     not be reported in the InnerClasses
     table.

For details it's the best to check SI-4819, SI-4820 and
SI-4983.

First problem mentioned above was straightforward to
fix so I won't be going into details.

The second one deserves more attention. From now, classes
corresponding to objects are properly reported as inner
classes. Also, members (classes, objects) of objects are
reported as inner classes of classes corresponding to
objects.

There's one caveat though: top level objects get two
classes (regular and mirror). Members of top-level
objects are declared as inner classes of *mirror* class
and not regular one. The reason for that is to allow
importing them from Java. For example:

object A { class B }

will be compiled into following classes: A, A$, A$B.
If we declared A$B as inner class of A$ (regular class
for objects) then it would be impossible to import
B using "import A.B" or "import A$.B" constructs. The
reason for that is that Java compiler seems to blindly
put dollars instead of looking at InnerClasses attribute.

Since non-top-level objects don't have a mirror class
it's impossible to use the same solution. Thus, in case
like this:

object A { object B { class C } }

it's impossible to import C from Java. That's the tradeoff
for fixing other (more serious) problems. It's never been
possible to do that in a clean way so we are not making
situation worse.

As a nice consequence of this change, we get better way to
refer to inner members of top-level objects. It's been
reflected in one of test-cases that is updated by this
change.

Fixes SI-4789 SI-4819	SI-4820 SI-4983 and possibly some
other tickets related to reflection.

Review by extempore, dragos.


git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@25639 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
grek 2011-09-09 20:56:19 +00:00
parent cbb09f5895
commit 32af28fb0c
2 changed files with 37 additions and 12 deletions

View File

@ -210,13 +210,39 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
val emitLines = debugLevel >= 2
val emitVars = debugLevel >= 3
/** For given symbol return a symbol corresponding to a class that should be declared as inner class.
*
* For example:
* class A {
* class B
* object C
* }
*
* then method will return NoSymbol for A, the same symbol for A.B (corresponding to A$B class) and A$C$ symbol
* for A.C.
*/
private def innerClassSymbolFor(s: Symbol): Symbol =
if (s.isClass) s else if (s.isModule) s.moduleClass else NoSymbol
override def javaName(sym: Symbol): String = {
val isInner = sym.isClass && !sym.rawowner.isPackageClass && !sym.isModuleClass
// TODO: something atPhase(currentRun.flattenPhase.prev) which accounts for
// being nested in parameterized classes (if we're going to selectively flatten.)
if (isInner && !innerClassBuffer(sym))
innerClassBuffer += sym
/**
* Checks if given symbol corresponds to inner class/object and add it to innerClassBuffer
*
* Note: This method is called recursively thus making sure that we add complete chain
* of inner class all until root class.
*/
def collectInnerClass(s: Symbol): Unit = {
// TODO: something atPhase(currentRun.flattenPhase.prev) which accounts for
// being nested in parameterized classes (if we're going to selectively flatten.)
val x = innerClassSymbolFor(s)
val isInner = x.isClass && !x.rawowner.isPackageClass
if (isInner) {
innerClassBuffer += x
collectInnerClass(x.rawowner)
}
}
collectInnerClass(sym)
super.javaName(sym)
}
@ -736,13 +762,12 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
if (innerSym.isAnonymousClass || innerSym.isAnonymousFunction)
null
else
innerSym.rawname.toString
innerSym.rawname + innerSym.moduleSuffix
// add inner classes which might not have been referenced yet
atPhase(currentRun.erasurePhase.next) {
for (sym <- List(clasz.symbol, clasz.symbol.linkedClassOfClass) ; m <- sym.info.decls ; if m.isClass)
if (!innerClassBuffer(m))
innerClassBuffer += m
for (sym <- List(clasz.symbol, clasz.symbol.linkedClassOfClass); m <- sym.info.decls.map(innerClassSymbolFor) if m.isClass)
innerClassBuffer += m
}
val allInners = innerClassBuffer.toList

View File

@ -21,13 +21,13 @@ class B { };
// we are informed if the status changes.
class Contra {
// Not an Ordering<Character>.
static Ordering<Object> charOrd = scala.math.Ordering$Char$.MODULE$;
static Ordering<Object> charOrd = scala.math.Ordering.Char$.MODULE$;
public boolean useCharOrd() {
return charOrd.compare(new Object(), new Object()) == 0;
}
static Numeric<?> intNum = scala.math.Numeric$IntIsIntegral$.MODULE$;
static Numeric<?> intNum = scala.math.Numeric.IntIsIntegral$.MODULE$;
}
public class fromjava {