summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2011-09-09 20:56:19 +0000
committerGrzegorz Kossakowski <grzegorz.kossakowski@gmail.com>2011-09-09 20:56:19 +0000
commitbcdd1882f159105db6d748f704839c65491f76d5 (patch)
tree74cf180043ffc0a2119c46ad76fe26ae710f1b8d
parentca15d245fd8624392756df5e79f893bea8ce53ef (diff)
downloadscala-bcdd1882f159105db6d748f704839c65491f76d5.tar.gz
scala-bcdd1882f159105db6d748f704839c65491f76d5.tar.bz2
scala-bcdd1882f159105db6d748f704839c65491f76d5.zip
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.
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala43
-rw-r--r--test/files/pos/javaReadsSigs/fromjava.java4
2 files changed, 36 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 48b5d7cdce..a231a67049 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -210,12 +210,38 @@ 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
diff --git a/test/files/pos/javaReadsSigs/fromjava.java b/test/files/pos/javaReadsSigs/fromjava.java
index 745fb84efd..92441b0c6b 100644
--- a/test/files/pos/javaReadsSigs/fromjava.java
+++ b/test/files/pos/javaReadsSigs/fromjava.java
@@ -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 {