summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2010-11-13 13:31:49 +0000
committerIulian Dragos <jaguarul@gmail.com>2010-11-13 13:31:49 +0000
commitd205bf404fb361de6c8829d8f13d8adcc809e87d (patch)
tree4fab6cd12183a287cdaf20d5700ee6185f492ce5 /src
parent8c5af3304f8592fbb2fe20db4caf61f1085b8723 (diff)
downloadscala-d205bf404fb361de6c8829d8f13d8adcc809e87d.tar.gz
scala-d205bf404fb361de6c8829d8f13d8adcc809e87d.tar.bz2
scala-d205bf404fb361de6c8829d8f13d8adcc809e87d.zip
Fix InnerClasses attribute: anonymous classes d...
Fix InnerClasses attribute: anonymous classes don't have an outer name. EnclosingMethod is correctly generated. Fixed isAnonymousClass definition. Updated test that depends on anonymous inner class names. Closes (again) #3249, references #2749. review by odersky,extempore.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala42
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala22
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java9
4 files changed, 57 insertions, 18 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 0c7455c6c8..384dfacbc8 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -200,7 +200,7 @@ abstract class GenJVM extends SubComponent {
def genClass(c: IClass) {
val needsEnclosingMethod: Boolean =
- c.symbol.isClass && c.symbol.asInstanceOf[ClassSymbol].originalOwner.isMethod
+ c.symbol.isClass && (c.symbol.originalEnclosingMethod != NoSymbol)
clasz = c
innerClasses = immutable.ListSet.empty
@@ -293,11 +293,13 @@ abstract class GenJVM extends SubComponent {
}
def addEnclosingMethodAttribute(jclass: JClass, clazz: Symbol) {
- val sym = clazz.asInstanceOf[ClassSymbol].originalOwner
+ val sym = clazz.originalEnclosingMethod
if (sym.isMethod) {
- jclass.addAttribute(fjbgContext.JEnclosingMethodAttribute(jclass, javaName(sym.enclClass), javaName(sym), javaType(sym)))
- } else
- log("Local class %s has non-method owner: %s".format(clazz, sym))
+ log("enclosing method for %s is %s".format(clazz, sym))
+ var outerName = javaName(sym.enclClass)
+ if (outerName.endsWith("$")) outerName = outerName.dropRight(1)
+ jclass.addAttribute(fjbgContext.JEnclosingMethodAttribute(jclass, outerName, javaName(sym), javaType(sym)))
+ }
}
/**
@@ -580,6 +582,28 @@ abstract class GenJVM extends SubComponent {
def addOwnInnerClasses(cls: Symbol): Unit =
innerClasses ++= (cls.info.decls filter (_.isClass))
+ /** The outer name for this inner class. Note that it returns null
+ * when the inner class should not get an index in the constant pool.
+ * That means non-member classes (anonymous). See Section 4.7.5 in the JVMS.
+ */
+ def outerName(innerSym: Symbol): String = {
+ if (innerSym.isAnonymousClass || innerSym.isAnonymousFunction || innerSym.originalEnclosingMethod != NoSymbol)
+ null
+ else {
+ var outerName = javaName(innerSym.rawowner)
+ // remove the trailing '$'
+ if (outerName.endsWith("$") && isTopLevelModule(innerSym.rawowner))
+ outerName = outerName dropRight 1
+ outerName
+ }
+ }
+
+ def innerName(innerSym: Symbol): String =
+ if (innerSym.isAnonymousClass || innerSym.isAnonymousFunction)
+ null
+ else
+ innerSym.rawname.toString
+
// add inner classes which might not have been referenced yet
atPhase(currentRun.erasurePhase.next) {
addOwnInnerClasses(clasz.symbol)
@@ -591,17 +615,13 @@ abstract class GenJVM extends SubComponent {
// sort them so inner classes succeed their enclosing class
// to satisfy the Eclipse Java compiler
for (innerSym <- innerClasses.toList sortBy (_.name.length)) {
- var outerName = javaName(innerSym.rawowner)
- // remove the trailing '$'
- if (outerName.endsWith("$") && isTopLevelModule(innerSym.rawowner))
- outerName = outerName dropRight 1
var flags = javaFlags(innerSym)
if (innerSym.rawowner.hasModuleFlag)
flags |= ACC_STATIC
innerClassesAttr.addEntry(javaName(innerSym),
- outerName,
- innerSym.rawname.toString,
+ outerName(innerSym),
+ innerName(innerSym),
(flags & INNER_CLASSES_FLAGS));
}
}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index fb1e705a56..695e95b72d 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -118,7 +118,7 @@ abstract class SymbolLoaders {
module.moduleClass setInfo moduleClassLoader
owner.info.decls enter clazz
owner.info.decls enter module
- assert(clazz.companionModule == module, module)
+ assert(clazz.companionModule == module || clazz.isAnonymousClass, module)
assert(module.companionClass == clazz, clazz)
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index d94b617904..8aa9c716c9 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -41,6 +41,11 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
abstract class Symbol(initOwner: Symbol, initPos: Position, initName: Name) extends AbsSymbol {
var rawowner = initOwner
+
+ /** The original owner of this class. Used by the backend to generate
+ * EnclosingMethod attributes. */
+ var originalOwner: Symbol = initOwner
+
var rawname = initName
var rawflags: Long = 0
private var rawpos = initPos
@@ -369,7 +374,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
// class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor
final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR)
- final def isAnonymousClass = isClass && (originalName startsWith nme.ANON_CLASS_NAME) // todo: find out why we can't use containsName here.
+ final def isAnonymousClass = isClass && (name containsName nme.ANON_CLASS_NAME) // todo: find out why we can't use containsName here.
final def isAnonymousFunction = hasFlag(SYNTHETIC) && (name containsName nme.ANON_FUN_NAME)
final def isClassOfModule = isModuleClass || isClass && nme.isLocalName(name)
@@ -1163,6 +1168,16 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
else packSym
}
+ /** Return the original enclosing method of this symbol. It
+ * should return the same thing as enclMethod when called before
+ * lambda lift, but it preserves the original nesting when called afterwards.
+ */
+ def originalEnclosingMethod: Symbol = {
+ if (isMethod) this
+ else
+ originalOwner.originalEnclosingMethod
+ }
+
/** The top-level class containing this symbol */
def toplevelClass: Symbol =
if (owner.isPackageClass) {
@@ -1897,10 +1912,6 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
/** The classfile from which this class was loaded. Maybe null. */
var classFile: AbstractFile = null;
- /** The original owner of this class. Used by the backend to generate
- * EnclosingMethod attributes. */
- var originalOwner: Symbol = initOwner
-
private var source: AbstractFile = null
override def sourceFile =
if (owner.isPackageClass) source else super.sourceFile
@@ -2031,6 +2042,7 @@ trait Symbols extends reflect.generic.Symbols { self: SymbolTable =>
protected def doCookJavaRawInfo() {}
override def accessBoundary(base: Symbol): Symbol = RootClass
def cloneSymbolImpl(owner: Symbol): Symbol = abort()
+ override def originalEnclosingMethod = this
}
def cloneSymbols(syms: List[Symbol]): List[Symbol] = {
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java b/src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java
index 81a7db7488..ac69d24947 100644
--- a/src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JInnerClassesAttribute.java
@@ -24,7 +24,14 @@ public class JInnerClassesAttribute extends JAttribute {
}
public void addEntry(String inner, String outer, String name, int flags) {
- Entry e = new Entry(inner, outer, name, flags);
+ int inIdx = pool.addClass(inner);
+ int ouIdx = 0;
+ if (outer != null) ouIdx = pool.addClass(outer);
+ int nIdx = 0;
+ if (name != null) nIdx = pool.addUtf8(name);
+
+ Entry e = new Entry(inIdx, ouIdx, nIdx, flags);
+
if (entries.containsKey(inner)) {
Entry other = (Entry) entries.get(inner);
assert other.outerInfo == e.outerInfo && other.originalName == e.originalName && other.innerFlags == e.innerFlags