Skip to content

Commit 5cc8574

Browse files
committed
Nuke trait implementation classes
- Leave the members in the trait instead (these will be emitted as default methods in the interface) - Add the trait mixin constructor to the interface, rather than the impl class - Change the invocation of the mixin constructor to use an invokespecial. This is encoded with the AST: `Apply(Select(Super(_, _), mixinConstructor)))` I've tried to remove all traces of the interface / implclass distinction.
1 parent 60ac55a commit 5cc8574

26 files changed

+117
-783
lines changed

src/compiler/scala/tools/nsc/ast/TreeGen.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
145145
override def mkCast(tree: Tree, pt: Type): Tree = {
146146
debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase)
147147
assert(!tree.tpe.isInstanceOf[MethodType], tree)
148+
assert(!pt.isInstanceOf[MethodType], tree)
148149
assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize))
149150
atPos(tree.pos) {
150151
mkAsInstanceOf(tree, pt, any = !phase.next.erasedTypes, wrapInApply = isAtPhaseAfter(currentRun.uncurryPhase))

src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
10331033
hostSymbol.info ; methodOwner.info
10341034

10351035
def needsInterfaceCall(sym: Symbol) = (
1036-
sym.isInterface
1036+
sym.isTraitOrInterface
10371037
|| sym.isJavaDefined && sym.isNonBottomSubClass(definitions.ClassfileAnnotationClass)
10381038
)
10391039

@@ -1327,7 +1327,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
13271327
def asmType(sym: Symbol) = classBTypeFromSymbol(sym).toASMType
13281328

13291329
val implMethodHandle =
1330-
new asm.Handle(if (lambdaTarget.hasFlag(Flags.STATIC)) asm.Opcodes.H_INVOKESTATIC else if (lambdaTarget.isTrait) asm.Opcodes.H_INVOKEINTERFACE else asm.Opcodes.H_INVOKEVIRTUAL,
1330+
new asm.Handle(if (lambdaTarget.hasFlag(Flags.STATIC)) asm.Opcodes.H_INVOKESTATIC else if (lambdaTarget.owner.isTrait) asm.Opcodes.H_INVOKEINTERFACE else asm.Opcodes.H_INVOKEVIRTUAL,
13311331
classBTypeFromSymbol(lambdaTarget.owner).internalName,
13321332
lambdaTarget.name.toString,
13331333
methodBTypeFromSymbol(lambdaTarget).descriptor)

src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
3232
* the InnerClass / EnclosingMethod classfile attributes. See comment in BTypes.
3333
*/
3434
def considerAsTopLevelImplementationArtifact(classSym: Symbol) = {
35-
classSym.isImplClass || classSym.isSpecialized
35+
classSym.isSpecialized
3636
}
3737

3838
/**
@@ -252,7 +252,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
252252
* Build the [[InlineInfo]] for a class symbol.
253253
*/
254254
def buildInlineInfoFromClassSymbol(classSym: Symbol, classSymToInternalName: Symbol => InternalName, methodSymToDescriptor: Symbol => String): InlineInfo = {
255-
val traitSelfType = if (classSym.isTrait && !classSym.isImplClass) {
255+
val traitSelfType = if (classSym.isTrait) {
256256
// The mixin phase uses typeOfThis for the self parameter in implementation class methods.
257257
val selfSym = classSym.typeOfThis.typeSymbol
258258
if (selfSym != classSym) Some(classSymToInternalName(selfSym)) else None
@@ -263,7 +263,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
263263
val isEffectivelyFinal = classSym.isEffectivelyFinal
264264

265265
val sam = {
266-
if (classSym.isImplClass || classSym.isEffectivelyFinal) None
266+
if (classSym.isEffectivelyFinal) None
267267
else {
268268
// Phase travel necessary. For example, nullary methods (getter of an abstract val) get an
269269
// empty parameter list in later phases and would therefore be picked as SAM.
@@ -297,7 +297,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
297297
// flag is ignored. The members are therefore not isEffectivelyFinal (their owner
298298
// is not a module). Since we know that all impl class members are static, we can
299299
// just take the shortcut.
300-
val effectivelyFinal = classSym.isImplClass || exitingPickler(methodSym.isEffectivelyFinalOrNotOverridden)
300+
val effectivelyFinal = exitingPickler(methodSym.isEffectivelyFinalOrNotOverridden)
301301

302302
// Identify trait interface methods that have a static implementation in the implementation
303303
// class. Invocations of these methods can be re-wrired directly to the static implementation
@@ -314,7 +314,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
314314
// properties manually.
315315
val traitMethodWithStaticImplementation = {
316316
import symtab.Flags._
317-
classSym.isTrait && !classSym.isImplClass &&
317+
classSym.isTrait &&
318318
erasure.needsImplMethod(methodSym) &&
319319
!methodSym.isModule &&
320320
!(methodSym hasFlag (ACCESSOR | SUPERACCESSOR))
@@ -862,7 +862,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
862862
|| sym.isArtifact
863863
|| sym.isLiftedMethod
864864
|| sym.isBridge
865-
|| (sym.ownerChain exists (_.isImplClass))
866865
)
867866

868867
/* @return

src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
176176
if (lmoc != NoSymbol) {
177177
// it must be a top level class (name contains no $s)
178178
val isCandidateForForwarders = {
179-
exitingPickler { !(lmoc.name.toString contains '$') && lmoc.hasModuleFlag && !lmoc.isImplClass && !lmoc.isNestedClass }
179+
exitingPickler { !(lmoc.name.toString contains '$') && lmoc.hasModuleFlag && !lmoc.isNestedClass }
180180
}
181181
if (isCandidateForForwarders) {
182182
log(s"Adding static forwarders from '$claszSymbol' to implementations in '$lmoc'")

src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
151151
*/
152152
def primitiveOrClassToBType(sym: Symbol): BType = {
153153
assertClassNotArray(sym)
154-
assert(!sym.isImplClass, sym)
155154
primitiveTypeMap.getOrElse(sym, classBTypeFromSymbol(sym))
156155
}
157156

@@ -320,7 +319,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
320319
// Check for hasAnnotationFlag for SI-9393: the classfile / java source parsers add
321320
// scala.annotation.Annotation as superclass to java annotations. In reality, java
322321
// annotation classfiles have superclass Object (like any interface classfile).
323-
val superClassSym = if (classSym.isImplClass || classSym.hasJavaAnnotationFlag) ObjectClass else {
322+
val superClassSym = if (classSym.hasJavaAnnotationFlag) ObjectClass else {
324323
val sc = classSym.superClass
325324
// SI-9393: Java annotation classes don't have the ABSTRACT/INTERFACE flag, so they appear
326325
// (wrongly) as superclasses. Fix this for BTypes: the java annotation will appear as interface
@@ -586,11 +585,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
586585
*/
587586
final def isTopLevelModuleClass(sym: Symbol): Boolean = exitingPickler {
588587
// phase travel to pickler required for isNestedClass (looks at owner)
589-
val r = sym.isModuleClass && !sym.isNestedClass
590-
// The mixin phase adds the `lateMODULE` flag to trait implementation classes. Since the flag
591-
// is late, it should not be visible here inside the time travel. We check this.
592-
if (r) assert(!sym.isImplClass, s"isModuleClass should be false for impl class $sym")
593-
r
588+
sym.isModuleClass && !sym.isNestedClass
594589
}
595590

596591
/**
@@ -667,7 +662,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
667662

668663
val finalFlag = (
669664
(((sym.rawflags & symtab.Flags.FINAL) != 0) || isTopLevelModuleClass(sym))
670-
&& !sym.enclClass.isInterface
665+
&& !sym.enclClass.isTrait
671666
&& !sym.isClassConstructor
672667
&& (!sym.isMutable || nme.isTraitSetterName(sym.name)) // lazy vals and vars and their setters cannot be final, but trait setters are
673668
)
@@ -680,12 +675,12 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
680675
GenBCode.mkFlags(
681676
if (privateFlag) ACC_PRIVATE else ACC_PUBLIC,
682677
if ((sym.isDeferred && !sym.hasFlag(symtab.Flags.JAVA_DEFAULTMETHOD))|| sym.hasAbstractFlag) ACC_ABSTRACT else 0,
683-
if (sym.isInterface) ACC_INTERFACE else 0,
678+
if (sym.isTraitOrInterface) ACC_INTERFACE else 0,
684679
if (finalFlag && !sym.hasAbstractFlag) ACC_FINAL else 0,
685680
if (sym.isStaticMember) ACC_STATIC else 0,
686681
if (sym.isBridge) ACC_BRIDGE | ACC_SYNTHETIC else 0,
687682
if (sym.isArtifact) ACC_SYNTHETIC else 0,
688-
if (sym.isClass && !sym.isInterface) ACC_SUPER else 0,
683+
if (sym.isClass && !sym.isTraitOrInterface) ACC_SUPER else 0,
689684
if (sym.hasJavaEnumFlag) ACC_ENUM else 0,
690685
if (sym.isVarargsMethod) ACC_VARARGS else 0,
691686
if (sym.hasFlag(symtab.Flags.SYNCHRONIZED)) ACC_SYNCHRONIZED else 0,

0 commit comments

Comments
 (0)