@@ -28,10 +28,9 @@ import scala.tools.nsc.settings.ScalaSettings
2828class BTypesFromSymbols [G <: Global ](val global : G ) extends BTypes {
2929 import global ._
3030 import definitions ._
31+ import genBCode ._
3132
3233 val bCodeICodeCommon : BCodeICodeCommon [global.type ] = new BCodeICodeCommon (global)
33- val bCodeAsmCommon : BCodeAsmCommon [global.type ] = new BCodeAsmCommon (global)
34- import bCodeAsmCommon ._
3534
3635 val backendUtils : BackendUtils [this .type ] = new BackendUtils (this )
3736
@@ -220,7 +219,101 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
220219 assert(! primitiveTypeMap.contains(sym) || isCompilingPrimitive, sym)
221220 }
222221
222+ def implementedInterfaces (classSym : Symbol ): List [Symbol ] = {
223+ // Additional interface parents based on annotations and other cues
224+ def newParentForAnnotation (ann : AnnotationInfo ): Option [Type ] = ann.symbol match {
225+ case RemoteAttr => Some (RemoteInterfaceClass .tpe)
226+ case _ => None
227+ }
228+
229+ // SI-9393: java annotations are interfaces, but the classfile / java source parsers make them look like classes.
230+ def isInterfaceOrTrait (sym : Symbol ) = sym.isInterface || sym.isTrait || sym.hasJavaAnnotationFlag
231+
232+ val classParents = {
233+ val parents = classSym.info.parents
234+ // SI-9393: the classfile / java source parsers add Annotation and ClassfileAnnotation to the
235+ // parents of a java annotations. undo this for the backend (where we need classfile-level information).
236+ if (classSym.hasJavaAnnotationFlag) parents.filterNot(c => c.typeSymbol == ClassfileAnnotationClass || c.typeSymbol == AnnotationClass )
237+ else parents
238+ }
239+
240+ val allParents = classParents ++ classSym.annotations.flatMap(newParentForAnnotation)
241+
242+ // We keep the superClass when computing minimizeParents to eliminate more interfaces.
243+ // Example: T can be eliminated from D
244+ // trait T
245+ // class C extends T
246+ // class D extends C with T
247+ val interfaces = erasure.minimizeParents(allParents) match {
248+ case superClass :: ifs if ! isInterfaceOrTrait(superClass.typeSymbol) =>
249+ ifs
250+ case ifs =>
251+ // minimizeParents removes the superclass if it's redundant, for example:
252+ // trait A
253+ // class C extends Object with A // minimizeParents removes Object
254+ ifs
255+ }
256+ interfaces.map(_.typeSymbol)
257+ }
258+
259+ /**
260+ * The member classes of a class symbol. Note that the result of this method depends on the
261+ * current phase, for example, after lambdalift, all local classes become member of the enclosing
262+ * class.
263+ *
264+ * Impl classes are always considered top-level, see comment in BTypes.
265+ */
266+ private def memberClassesForInnerClassTable (classSymbol : Symbol ): List [Symbol ] = classSymbol.info.decls.collect({
267+ case sym if sym.isClass && ! considerAsTopLevelImplementationArtifact(sym) =>
268+ sym
269+ case sym if sym.isModule && ! considerAsTopLevelImplementationArtifact(sym) => // impl classes get the lateMODULE flag in mixin
270+ val r = exitingPickler(sym.moduleClass)
271+ assert(r != NoSymbol , sym.fullLocationString)
272+ r
273+ })(collection.breakOut)
274+
223275 private def setClassInfo (classSym : Symbol , classBType : ClassBType ): ClassBType = {
276+ /**
277+ * Reconstruct the classfile flags from a Java defined class symbol.
278+ *
279+ * The implementation of this method is slightly different from `javaFlags` in BTypesFromSymbols.
280+ * The javaFlags method is primarily used to map Scala symbol flags to sensible classfile flags
281+ * that are used in the generated classfiles. For example, all classes emitted by the Scala
282+ * compiler have ACC_PUBLIC.
283+ *
284+ * When building a [[ClassBType ]] from a Java class symbol, the flags in the type's `info` have
285+ * to correspond exactly to the flags in the classfile. For example, if the class is package
286+ * protected (i.e., it doesn't have the ACC_PUBLIC flag), this needs to be reflected in the
287+ * ClassBType. For example, the inliner needs the correct flags for access checks.
288+ *
289+ * Class flags are listed here:
290+ * https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.1-200-E.1
291+ */
292+ def javaClassfileFlags (classSym : Symbol ): Int = {
293+ assert(classSym.isJava, s " Expected Java class symbol, got ${classSym.fullName}" )
294+ import asm .Opcodes ._
295+ def enumFlags = ACC_ENUM | {
296+ // Java enums have the `ACC_ABSTRACT` flag if they have a deferred method.
297+ // We cannot trust `hasAbstractFlag`: the ClassfileParser adds `ABSTRACT` and `SEALED` to all
298+ // Java enums for exhaustiveness checking.
299+ val hasAbstractMethod = classSym.info.decls.exists(s => s.isMethod && s.isDeferred)
300+ if (hasAbstractMethod) ACC_ABSTRACT else 0
301+ }
302+ GenBCode .mkFlags(
303+ // SI-9393: the classfile / java source parser make java annotation symbols look like classes.
304+ // here we recover the actual classfile flags.
305+ if (classSym.hasJavaAnnotationFlag) ACC_ANNOTATION | ACC_INTERFACE | ACC_ABSTRACT else 0 ,
306+ if (classSym.isPublic) ACC_PUBLIC else 0 ,
307+ if (classSym.isFinal) ACC_FINAL else 0 ,
308+ // see the link above. javac does the same: ACC_SUPER for all classes, but not interfaces.
309+ if (classSym.isInterface) ACC_INTERFACE else ACC_SUPER ,
310+ // for Java enums, we cannot trust `hasAbstractFlag` (see comment in enumFlags)
311+ if (! classSym.hasJavaEnumFlag && classSym.hasAbstractFlag) ACC_ABSTRACT else 0 ,
312+ if (classSym.isArtifact) ACC_SYNTHETIC else 0 ,
313+ if (classSym.hasJavaEnumFlag) enumFlags else 0
314+ )
315+ }
316+
224317 // Check for isImplClass: trait implementation classes have NoSymbol as superClass
225318 // Check for hasAnnotationFlag for SI-9393: the classfile / java source parsers add
226319 // scala.annotation.Annotation as superclass to java annotations. In reality, java
0 commit comments