summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala284
-rw-r--r--test/files/run/bug3487.scala15
2 files changed, 146 insertions, 153 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 49d3251448..7be9475f23 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -9,15 +9,16 @@ package backend.jvm
import java.nio.ByteBuffer
-import scala.collection.immutable.{Set, ListSet}
-import scala.collection.mutable.{Map, HashMap, HashSet}
+import scala.collection.{ mutable, immutable }
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.symtab._
import scala.tools.nsc.symtab.classfile.ClassfileConstants._
import ch.epfl.lamp.fjbg._
-import java.io.{ByteArrayOutputStream, DataOutputStream, File, OutputStream}
-import reflect.generic.{PickleFormat, PickleBuffer}
+import JAccessFlags._
+import JObjectType.{ JAVA_LANG_STRING, JAVA_LANG_OBJECT }
+import java.io.{ DataOutputStream }
+import reflect.generic.{ PickleFormat, PickleBuffer }
/** This class ...
*
@@ -32,7 +33,9 @@ abstract class GenJVM extends SubComponent {
import definitions.{
NullClass, RuntimeNullClass, NothingClass, RuntimeNothingClass,
AnyClass, ObjectClass, ThrowsClass, ThrowableClass, ClassfileAnnotationClass,
- DeprecatedAttr,
+ SerializableClass, StringClass, ClassClass, FunctionClass,
+ DeprecatedAttr, SerializableAttr, SerialVersionUIDAttr, VolatileAttr,
+ TransientAttr, CloneableAttr, RemoteAttr,
getPrimitiveCompanion
}
@@ -77,8 +80,6 @@ abstract class GenJVM extends SubComponent {
*
*/
class BytecodeGenerator {
- import JAccessFlags._
-
def debugLevel = settings.debuginfo.indexOfChoice
val MIN_SWITCH_DENSITY = 0.7
@@ -92,14 +93,13 @@ abstract class GenJVM extends SubComponent {
val BoxesRunTime = "scala.runtime.BoxesRunTime"
val StringBuilderType = new JObjectType(StringBuilderClass)
- val toStringType = new JMethodType(JObjectType.JAVA_LANG_STRING, JType.EMPTY_ARRAY)
- val arrayCloneType = new JMethodType(JObjectType.JAVA_LANG_OBJECT, JType.EMPTY_ARRAY)
+ val toStringType = new JMethodType(JAVA_LANG_STRING, JType.EMPTY_ARRAY)
+ val arrayCloneType = new JMethodType(JAVA_LANG_OBJECT, JType.EMPTY_ARRAY)
val MethodTypeType = new JObjectType("java.dyn.MethodType")
val JavaLangClassType = new JObjectType("java.lang.Class")
val MethodHandleType = new JObjectType("java.dyn.MethodHandle")
// Scala attributes
- import definitions.{ SerializableAttr, SerialVersionUIDAttr, VolatileAttr, TransientAttr, CloneableAttr, RemoteAttr }
val BeanInfoAttr = definitions.getClass("scala.reflect.BeanInfo")
val BeanInfoSkipAttr = definitions.getClass("scala.reflect.BeanInfoSkip")
val BeanDisplayNameAttr = definitions.getClass("scala.reflect.BeanDisplayName")
@@ -130,7 +130,7 @@ abstract class GenJVM extends SubComponent {
var jmethod: JMethod = _
// var jcode: JExtendedCode = _
- var innerClasses: Set[Symbol] = ListSet.empty // referenced inner classes
+ var innerClasses: immutable.Set[Symbol] = immutable.ListSet.empty // referenced inner classes
val fjbgContext = new FJBGContext(49, 0)
@@ -200,7 +200,7 @@ abstract class GenJVM extends SubComponent {
def genClass(c: IClass) {
clasz = c
- innerClasses = ListSet.empty
+ innerClasses = immutable.ListSet.empty
var parents = c.symbol.info.parents
var ifaces = JClass.NO_INTERFACES
@@ -211,11 +211,11 @@ abstract class GenJVM extends SubComponent {
(parents contains ParcelableInterface.tpe)
if (parents.isEmpty)
- parents = ObjectClass.tpe :: parents;
+ parents = List(ObjectClass.tpe)
for (annot <- c.symbol.annotations) annot match {
case AnnotationInfo(tp, _, _) if tp.typeSymbol == SerializableAttr =>
- parents = parents ::: List(definitions.SerializableClass.tpe)
+ parents = parents ::: List(SerializableClass.tpe)
case AnnotationInfo(tp, _, _) if tp.typeSymbol == CloneableAttr =>
parents = parents ::: List(CloneableClass.tpe)
case AnnotationInfo(tp, Literal(const) :: _, _) if tp.typeSymbol == SerialVersionUIDAttr =>
@@ -267,7 +267,7 @@ abstract class GenJVM extends SubComponent {
// add static forwarders if there are no name conflicts; see bugs #363 and #1735
if (lmoc != NoSymbol && !c.symbol.hasFlag(Flags.INTERFACE)) {
if (isCandidateForForwarders(lmoc) && !settings.noForwarders.value) {
- log("Adding forwarders to existing class '%s' found in module '%s'".format(c.symbol, lmoc))
+ log("Adding static forwarders from '%s' to implementations in '%s'".format(c.symbol, lmoc))
addForwarders(jclass, lmoc.moduleClass)
}
}
@@ -320,9 +320,9 @@ abstract class GenJVM extends SubComponent {
val constructor = beanInfoClass.addNewMethod(ACC_PUBLIC, "<init>", JType.VOID, javaTypes(Nil), javaNames(Nil))
val jcode = constructor.getCode().asInstanceOf[JExtendedCode]
- val strKind = new JObjectType(javaName(definitions.StringClass))
+ val strKind = new JObjectType(javaName(StringClass))
val stringArrayKind = new JArrayType(strKind)
- val conType = new JMethodType(JType.VOID, Array(javaType(definitions.ClassClass), stringArrayKind, stringArrayKind))
+ val conType = new JMethodType(JType.VOID, Array(javaType(ClassClass), stringArrayKind, stringArrayKind))
def push(lst:Seq[String]) {
var fi = 0
@@ -498,17 +498,15 @@ abstract class GenJVM extends SubComponent {
val memberTpe = atPhase(currentRun.erasurePhase)(owner.thisType.memberInfo(sym))
// println("addGenericSignature sym: " + sym.fullName + " : " + memberTpe + " sym.info: " + sym.info)
// println("addGenericSignature: "+ (sym.ownerChain map (x => (x.name, x.isImplClass))))
- erasure.javaSig(sym, memberTpe) match {
- case Some(sig) =>
- val index = jmember.getConstantPool().addUtf8(sig).toShort
- if (settings.debug.value && settings.verbose.value)
- atPhase(currentRun.erasurePhase) {
- println("add generic sig "+sym+":"+sym.info+" ==> "+sig+" @ "+index)
- }
- val buf = ByteBuffer.allocate(2)
- buf.putShort(index)
- addAttribute(jmember, nme.SignatureATTR, buf)
- case None =>
+ erasure.javaSig(sym, memberTpe) foreach { sig =>
+ val index = jmember.getConstantPool().addUtf8(sig).toShort
+ if (settings.debug.value && settings.verbose.value)
+ atPhase(currentRun.erasurePhase) {
+ println("add generic sig "+sym+":"+sym.info+" ==> "+sig+" @ "+index)
+ }
+ val buf = ByteBuffer.allocate(2)
+ buf.putShort(index)
+ addAttribute(jmember, nme.SignatureATTR, buf)
}
}
}
@@ -724,7 +722,7 @@ abstract class GenJVM extends SubComponent {
sym.owner.hasFlag(Flags.SYNTHETIC) &&
sym.owner.tpe.parents.exists { t =>
val TypeRef(_, sym, _) = t;
- definitions.FunctionClass exists sym.==
+ FunctionClass contains sym
}
}
@@ -757,17 +755,15 @@ abstract class GenJVM extends SubComponent {
}
// add serialVUID code
- serialVUID match {
- case Some(value) =>
- import Flags._, definitions._
- val fieldName = "serialVersionUID"
- val fieldSymbol = clasz.symbol.newValue(NoPosition, newTermName(fieldName))
- .setFlag(STATIC | FINAL)
- .setInfo(longType)
- clasz addField new IField(fieldSymbol)
- lastBlock emit CONSTANT(Constant(value))
- lastBlock emit STORE_FIELD(fieldSymbol, true)
- case None => ()
+ serialVUID foreach { value =>
+ import Flags._, definitions._
+ val fieldName = "serialVersionUID"
+ val fieldSymbol = clasz.symbol.newValue(NoPosition, newTermName(fieldName))
+ .setFlag(STATIC | FINAL)
+ .setInfo(longType)
+ clasz addField new IField(fieldSymbol)
+ lastBlock emit CONSTANT(Constant(value))
+ lastBlock emit STORE_FIELD(fieldSymbol, true)
}
// add CREATOR code
@@ -799,7 +795,6 @@ abstract class GenJVM extends SubComponent {
}
private def legacyStaticInitializer(cls: JClass, clinit: JExtendedCode) {
- import JAccessFlags._
if (isStaticModule(clasz.symbol)) {
clinit emitNEW cls.getName()
clinit.emitINVOKESPECIAL(cls.getName(),
@@ -807,20 +802,18 @@ abstract class GenJVM extends SubComponent {
JMethodType.ARGLESS_VOID_FUNCTION)
}
- serialVUID match {
- case Some(value) =>
- val fieldName = "serialVersionUID"
- jclass.addNewField(PublicStaticFinal, fieldName, JType.LONG)
- clinit emitPUSH value
- clinit.emitPUSH(value)
- clinit.emitPUTSTATIC(jclass.getName(), fieldName, JType.LONG)
- case None => ()
+ serialVUID foreach { value =>
+ val fieldName = "serialVersionUID"
+ jclass.addNewField(PublicStaticFinal, fieldName, JType.LONG)
+ clinit emitPUSH value
+ clinit.emitPUSH(value)
+ clinit.emitPUTSTATIC(jclass.getName(), fieldName, JType.LONG)
}
if (isParcelableClass) {
val fieldName = "CREATOR"
val creatorType = javaType(CreatorClass)
- jclass.addNewField(ACC_STATIC | ACC_PUBLIC | ACC_FINAL,
+ jclass.addNewField(PublicStaticFinal,
fieldName,
creatorType)
val moduleName = javaName(clasz.symbol)+"$"
@@ -847,28 +840,23 @@ abstract class GenJVM extends SubComponent {
jcode emitPUSH "bootstrapInvokeDynamic"
jcode.emitGETSTATIC("java.dyn.Linkage", "BOOTSTRAP_METHOD_TYPE", MethodTypeType)
jcode.emitDUP
- jcode.emitINVOKESTATIC("scala.Console", "println", new JMethodType(JType.VOID, Array(JObjectType.JAVA_LANG_OBJECT)))
+ jcode.emitINVOKESTATIC("scala.Console", "println", new JMethodType(JType.VOID, Array(JAVA_LANG_OBJECT)))
jcode.emitINVOKESTATIC("java.dyn.MethodHandles", "findStatic",
- new JMethodType(MethodHandleType, Array(JavaLangClassType, JObjectType.JAVA_LANG_STRING, MethodTypeType)))
+ new JMethodType(MethodHandleType, Array(JavaLangClassType, JAVA_LANG_STRING, MethodTypeType)))
jcode.emitINVOKESTATIC("java.dyn.Linkage", "registerBootstrapMethod",
new JMethodType(JType.VOID, Array(JavaLangClassType, MethodHandleType)))
}
/** Add a forwarder for method m */
- def addForwarder(jclass: JClass, module: Symbol, m: Symbol) {
- import JAccessFlags._
- val moduleName = javaName(module) // + "$"
- val mirrorName = moduleName dropRight 1
- val methodInfo = module.thisType.memberInfo(m)
-
+ def addForwarder(jclass: JClass, module: Symbol, m: Symbol, accessFlags: Int) {
+ val moduleName = javaName(module)
+ val mirrorName = moduleName dropRight 1 // dropping '$'
+ val methodInfo = module.thisType.memberInfo(m)
val paramJavaTypes = methodInfo.paramTypes map toTypeKind
- val paramNames: Array[String] = new Array[String](paramJavaTypes.length)
-
- for (i <- 0 until paramJavaTypes.length)
- paramNames(i) = "x_" + i
+ val paramNames = 0 until paramJavaTypes.length map ("x_" + _) toArray
val mirrorMethod = jclass.addNewMethod(
- PublicStaticFinal,
+ accessFlags,
javaName(m),
javaType(methodInfo.resultType),
javaTypes(paramJavaTypes),
@@ -877,6 +865,7 @@ abstract class GenJVM extends SubComponent {
mirrorCode.emitGETSTATIC(moduleName,
nme.MODULE_INSTANCE_FIELD.toString,
new JObjectType(moduleName))
+
var i = 0
var index = 0
var argTypes = mirrorMethod.getArgumentTypes()
@@ -903,69 +892,70 @@ abstract class GenJVM extends SubComponent {
/** Add forwarders for all methods defined in `module' that don't conflict
* with methods in the companion class of `module'. A conflict arises when
* a method with the same name is defined both in a class and its companion
- * object (method signature is not taken into account). If 3rd argument
- * `cond` is supplied, only symbols for which `cond(sym)` is true are
- * given forwarders.
+ * object: method signature is not taken into account.
*/
- def addForwarders(jclass: JClass, module: Symbol) { addForwarders(jclass, module, _ => true) }
- def addForwarders(jclass: JClass, module: Symbol, cond: (Symbol) => Boolean) {
- def conflictsIn(cls: Symbol, name: Name) =
- cls.info.members exists (_.name == name)
-
- /** List of parents shared by both class and module, so we don't add
- * forwarders for methods defined there - bug #1804 */
- lazy val commonParents = {
- val cps = module.info.baseClasses
- val mps = module.companionClass.info.baseClasses
- cps.filter(mps contains)
- }
- /* The setter doesn't show up in members so we inspect the name
- * ... and clearly it helps to know how the name is encoded, see ticket #3004.
- * This logic is grossly inadequate! Name mangling needs a devotee.
+ def addForwarders(jclass: JClass, moduleClass: Symbol) {
+ assert(moduleClass.isModuleClass)
+ val className = jclass.getName
+ val linkedClass = moduleClass.companionClass
+ val linkedModule = linkedClass.companionSymbol
+
+ /** If we use the usual algorithm for forwarders, we run into a problem if
+ * an object extends its companion class. However, there is an out: since
+ * all the forwarders are static, inheriting from the class is no problem
+ * so long as the methods aren't final (the JVM will not allow redefinition
+ * of a final static method.) Thus the following.
*/
- def conflictsInCommonParent(name: Name) =
- commonParents exists { cp =>
- (name startsWith (cp.name + "$")) || (name containsName ("$" + cp.name + "$"))
- }
+ val isIncestuous = moduleClass.tpe <:< linkedClass.tpe
+ val accessFlags = if (isIncestuous) PublicStatic else PublicStaticFinal
- /** Should method `m' get a forwarder in the mirror class? */
- def shouldForward(m: Symbol): Boolean =
- atPhase(currentRun.picklerPhase) (
- m.owner != ObjectClass
- && m.isMethod
- && !m.hasFlag(Flags.CASE | Flags.PRIVATE | Flags.PROTECTED | Flags.DEFERRED | Flags.SPECIALIZED)
- && !m.isConstructor
- && !m.isStaticMember
- && !(m.owner == AnyClass)
- && !module.isSubClass(module.companionClass)
- && !conflictsIn(ObjectClass, m.name)
- && !conflictsInCommonParent(m.name)
- && !conflictsIn(module.companionClass, m.name)
- )
-
- assert(module.isModuleClass)
- if (settings.debug.value)
- log("Dumping mirror class for object: " + module);
+ /** There was a bit of a gordian logic knot here regarding forwarders.
+ * All we really have to do is exclude certain categories of symbols and
+ * then all matching names.
+ */
+ def memberNames(sym: Symbol) = sym.info.members map (_.name.toString) toSet
+ lazy val membersInCommon = atPhase(currentRun.picklerPhase)(
+ memberNames(linkedModule) intersect memberNames(linkedClass)
+ )
- for (m <- module.info.nonPrivateMembers if shouldForward(m) && cond(m)) {
- log("Adding static forwarder '%s' to '%s'".format(m, module))
- addForwarder(jclass, module, m)
+ /** Should method `m' get a forwarder in the mirror class? */
+ def shouldForward(m: Symbol): Boolean = atPhase(currentRun.picklerPhase)(
+ m.owner != ObjectClass
+ && m.isMethod
+ && m.isPublic
+ && !m.hasFlag(Flags.CASE | Flags.DEFERRED | Flags.SPECIALIZED | Flags.LIFTED)
+ && !m.isConstructor
+ && !m.isStaticMember
+ && !membersInCommon(m.name.toString)
+ )
+
+ for (m <- moduleClass.info.nonPrivateMembers) {
+ if (shouldForward(m)) {
+ log("Adding static forwarder for '%s' from %s to '%s'".format(m, className, moduleClass))
+ addForwarder(jclass, moduleClass, m, accessFlags)
+ }
+ else if (settings.debug.value) {
+ log("No forwarder for '%s' from %s to '%s'".format(m, className, moduleClass))
+ }
}
}
/** Dump a mirror class for a top-level module. A mirror class is a class
* containing only static methods that forward to the corresponding method
- * on the MODULE instance of the given Scala object.
+ * on the MODULE instance of the given Scala object. It will only be
+ * generated if there is no companion class: if there is, an attempt will
+ * instead be made to add the forwarder methods to the companion class.
*/
def dumpMirrorClass(clasz: Symbol, sourceFile: String) {
- import JAccessFlags._
val moduleName = javaName(clasz) // + "$"
val mirrorName = moduleName dropRight 1
val mirrorClass = fjbgContext.JClass(ACC_SUPER | ACC_PUBLIC | ACC_FINAL,
mirrorName,
- "java.lang.Object",
+ JAVA_LANG_OBJECT.getName,
JClass.NO_INTERFACES,
sourceFile)
+
+ log("Dumping mirror class for '%s'".format(mirrorClass.getName))
addForwarders(mirrorClass, clasz)
val ssa = scalaSignatureAddingMarker(mirrorClass, clasz.companionSymbol)
addAnnotations(mirrorClass, clasz.annotations ++ ssa)
@@ -1016,7 +1006,7 @@ abstract class GenJVM extends SubComponent {
if (settings.debug.value)
log("Making labels for: " + method)
- HashMap(bs map (_ -> jcode.newLabel) : _*)
+ mutable.HashMap(bs map (_ -> jcode.newLabel) : _*)
}
isModuleInitialized = false
@@ -1024,7 +1014,7 @@ abstract class GenJVM extends SubComponent {
linearization = linearizer.linearize(m)
val labels = makeLabels(linearization)
/** local variables whose scope appears in this block. */
- var varsInBlock: collection.mutable.Set[Local] = new HashSet
+ var varsInBlock: mutable.Set[Local] = new mutable.HashSet
var nextBlock: BasicBlock = linearization.head
@@ -1232,7 +1222,7 @@ abstract class GenJVM extends SubComponent {
jcode.emitINVOKESTATIC(BoxesRunTime, "boxTo" + boxedType.decodedName, mtype)
case UNBOX(kind) =>
- val mtype = new JMethodType(javaType(kind), Array(JObjectType.JAVA_LANG_OBJECT))
+ val mtype = new JMethodType(javaType(kind), Array(JAVA_LANG_OBJECT))
jcode.emitINVOKESTATIC(BoxesRunTime, "unboxTo" + kind.toType.typeSymbol.decodedName, mtype)
case NEW(REFERENCE(cls)) =>
@@ -1626,7 +1616,7 @@ abstract class GenJVM extends SubComponent {
case StringConcat(el) =>
val jtype = el match {
- case REFERENCE(_) | ARRAY(_) => JObjectType.JAVA_LANG_OBJECT
+ case REFERENCE(_) | ARRAY(_) => JAVA_LANG_OBJECT
case _ => javaType(el)
}
jcode.emitINVOKEVIRTUAL(StringBuilderClass,
@@ -1706,8 +1696,8 @@ abstract class GenJVM extends SubComponent {
/** For each basic block, the first PC address following it. */
- val endPC: HashMap[BasicBlock, Int] = new HashMap()
- val conds: HashMap[TestOp, Int] = new HashMap()
+ val endPC = new mutable.HashMap[BasicBlock, Int]
+ val conds = new mutable.HashMap[TestOp, Int]
conds += (EQ -> JExtendedCode.COND_EQ)
conds += (NE -> JExtendedCode.COND_NE)
@@ -1716,7 +1706,7 @@ abstract class GenJVM extends SubComponent {
conds += (LE -> JExtendedCode.COND_LE)
conds += (GE -> JExtendedCode.COND_GE)
- val negate: HashMap[TestOp, TestOp] = new HashMap()
+ val negate = new mutable.HashMap[TestOp, TestOp]
negate += (EQ -> NE)
negate += (NE -> EQ)
@@ -1727,18 +1717,17 @@ abstract class GenJVM extends SubComponent {
/** Map from type kinds to the Java reference types. It is used for
* loading class constants. @see Predef.classOf. */
- val classLiteral: Map[TypeKind, JObjectType] = new HashMap()
-
- classLiteral += (UNIT -> new JObjectType("java.lang.Void"))
- classLiteral += (BOOL -> new JObjectType("java.lang.Boolean"))
- classLiteral += (BYTE -> new JObjectType("java.lang.Byte"))
- classLiteral += (SHORT -> new JObjectType("java.lang.Short"))
- classLiteral += (CHAR -> new JObjectType("java.lang.Character"))
- classLiteral += (INT -> new JObjectType("java.lang.Integer"))
- classLiteral += (LONG -> new JObjectType("java.lang.Long"))
- classLiteral += (FLOAT -> new JObjectType("java.lang.Float"))
- classLiteral += (DOUBLE -> new JObjectType("java.lang.Double"))
-
+ val classLiteral = immutable.Map[TypeKind, JObjectType](
+ UNIT -> new JObjectType("java.lang.Void"),
+ BOOL -> new JObjectType("java.lang.Boolean"),
+ BYTE -> new JObjectType("java.lang.Byte"),
+ SHORT -> new JObjectType("java.lang.Short"),
+ CHAR -> new JObjectType("java.lang.Character"),
+ INT -> new JObjectType("java.lang.Integer"),
+ LONG -> new JObjectType("java.lang.Long"),
+ FLOAT -> new JObjectType("java.lang.Float"),
+ DOUBLE -> new JObjectType("java.lang.Double")
+ )
////////////////////// local vars ///////////////////////
@@ -1821,6 +1810,7 @@ abstract class GenJVM extends SubComponent {
syms foreach (s => { res(i) = javaName(s); i += 1 })
res
}
+ private def mkFlags(args: Int*) = args.foldLeft(0)(_ | _)
/**
* Return the Java modifiers for the given symbol.
@@ -1839,32 +1829,20 @@ abstract class GenJVM extends SubComponent {
* and they would fail verification after lifted.
*/
def javaFlags(sym: Symbol): Int = {
- import JAccessFlags._
-
- var jf: Int = 0
- val f = sym.flags
-/* jf = jf | (if (sym hasFlag Flags.PRIVATE) ACC_PRIVATE else
- if (sym hasFlag Flags.PROTECTED) ACC_PROTECTED else ACC_PUBLIC)
-*/
- jf = jf | (if (sym hasFlag Flags.PRIVATE) ACC_PRIVATE else ACC_PUBLIC)
- jf = jf | (if ((sym hasFlag Flags.ABSTRACT) ||
- (sym hasFlag Flags.DEFERRED)) ACC_ABSTRACT else 0)
- jf = jf | (if (sym hasFlag Flags.INTERFACE) ACC_INTERFACE else 0)
- jf = jf | (if ((sym hasFlag Flags.FINAL)
- && !sym.enclClass.hasFlag(Flags.INTERFACE)
- && !sym.isClassConstructor) ACC_FINAL else 0)
- jf = jf | (if (sym.isStaticMember) ACC_STATIC else 0)
- jf = jf | (if (sym hasFlag Flags.BRIDGE) ACC_BRIDGE else 0)
-
- if (sym.isClass && !sym.hasFlag(Flags.INTERFACE))
- jf |= ACC_SUPER
-
// constructors of module classes should be private
- if (sym.isPrimaryConstructor && isTopLevelModule(sym.owner)) {
- jf |= ACC_PRIVATE
- jf &= ~ACC_PUBLIC
- }
- jf
+ // PP: why are they only being marked private at this stage and not earlier?
+ val isConsideredPrivate =
+ sym.isPrivate || (sym.isPrimaryConstructor && isTopLevelModule(sym.owner))
+
+ mkFlags(
+ if (isConsideredPrivate) ACC_PRIVATE else ACC_PUBLIC,
+ if (sym.isDeferred || sym.hasFlag(Flags.ABSTRACT)) ACC_ABSTRACT else 0,
+ if (sym.isInterface) ACC_INTERFACE else 0,
+ if (sym.isFinal && !sym.enclClass.isInterface && !sym.isClassConstructor) ACC_FINAL else 0,
+ if (sym.isStaticMember) ACC_STATIC else 0,
+ if (sym.isBridge) ACC_BRIDGE else 0,
+ if (sym.isClass && !sym.isInterface) ACC_SUPER else 0
+ )
}
/** Calls to methods in 'sym' need invokeinterface? */
diff --git a/test/files/run/bug3487.scala b/test/files/run/bug3487.scala
new file mode 100644
index 0000000000..f2ca735913
--- /dev/null
+++ b/test/files/run/bug3487.scala
@@ -0,0 +1,15 @@
+trait Bippy {
+ def bippy = 5
+}
+
+class Test extends Bippy {
+ def f1 = 55
+}
+
+object Test extends Test {
+ def dingus = bippy
+ def main(args: Array[String]): Unit = {
+ assert(bippy + f1 == 110)
+ }
+ override def bippy = 55
+}