Skip to content

Commit 24d24c8

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)))` This compiles a simple example: ``` trait T { def m = 42 } class C extends T object Test { def main(args: Array[String]): Unit = { assert(new C().m == 42) } } ``` To: ``` Compiled from "test.scala" public interface T { public void $init$(); Code: 0: return public int m(); Code: 0: bipush 42 2: ireturn } Compiled from "test.scala" public class C implements T { public C(); Code: 0: aload_0 1: invokespecial #14 // Method java/lang/Object."<init>":()V 4: aload_0 5: invokespecial #17 // Method T.$init$:()V 8: return } ``` We need to re-enable the "trait forwarder" method in `C`. Although in this example we can rely on Java's method binding rules to call the right `T.m`, in the general case when we have diamond inheritance we need to encode Scala's linearization rules. Adriaan explained this in some detail here: https://groups.google.com/forum/#!topic/scala-internals/KnxCpSryrSM For now I'm just starting with the happy path of public defs. Fields, non-public members, will also need a good helping of finesse. And modules, lazies.
1 parent 70d63bf commit 24d24c8

File tree

2 files changed

+36
-33
lines changed

2 files changed

+36
-33
lines changed

src/compiler/scala/tools/nsc/transform/AddInterfaces.scala

+35-32
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,8 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
211211

212212
def transformMixinInfo(tp: Type): Type = tp match {
213213
case ClassInfoType(parents, decls, clazz) if clazz.isPackageClass || !clazz.isJavaDefined =>
214-
if (clazz.needsImplClass)
215-
implClass(clazz setFlag lateINTERFACE) // generate an impl class
214+
// if (clazz.needsImplClass)
215+
// implClass(clazz setFlag lateINTERFACE) // generate an impl class
216216

217217
val parents1 = parents match {
218218
case Nil => Nil
@@ -223,10 +223,13 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
223223
}
224224
val decls1 = scopeTransform(clazz)(
225225
decls filter (sym =>
226-
if (clazz.isInterface) isInterfaceMember(sym)
226+
if (clazz.isInterface) {
227+
isInterfaceMember(sym) && { sym.setFlag(Flags.JAVA_DEFAULTMETHOD); true }
228+
}
227229
else sym.isClass || sym.isTerm
228230
)
229231
)
232+
if (clazz.isTrait) decls1.enter(decls enter (clazz.newMethod(nme.MIXIN_CONSTRUCTOR, clazz.pos, Flags.PROTECTED | Flags.ARTIFACT) setInfo MethodType(Nil, UnitTpe)))
230233
ClassInfoType(parents1, decls1, clazz)
231234
case _ =>
232235
tp
@@ -321,13 +324,13 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
321324
* to tree, which is assumed to be the body of a constructor of class clazz.
322325
*/
323326
private def addMixinConstructorCalls(tree: Tree, clazz: Symbol): Tree = {
324-
def mixinConstructorCall(impl: Symbol): Tree = atPos(tree.pos) {
325-
Apply(Select(This(clazz), impl.primaryConstructor), List())
327+
def mixinConstructorCall(mc: Symbol): Tree = atPos(tree.pos) {
328+
Apply(Select(Super(clazz, tpnme.EMPTY), mc.primaryConstructor), List())
326329
}
327330
val mixinConstructorCalls: List[Tree] = {
328331
for (mc <- clazz.mixinClasses.reverse
329-
if mc.hasFlag(lateINTERFACE))
330-
yield mixinConstructorCall(implClass(mc))
332+
if mc.isTrait)
333+
yield mixinConstructorCall(mc)
331334
}
332335
tree match {
333336
case Block(Nil, expr) =>
@@ -352,36 +355,36 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
352355
override def transform(tree: Tree): Tree = {
353356
val sym = tree.symbol
354357
val tree1 = tree match {
355-
case ClassDef(mods, _, _, impl) if sym.needsImplClass =>
356-
implClass(sym).initialize // to force lateDEFERRED flags
357-
copyClassDef(tree)(mods = mods | INTERFACE, impl = ifaceTemplate(impl))
358+
// case ClassDef(mods, _, _, impl) if sym.needsImplClass =>
359+
// implClass(sym).initialize // to force lateDEFERRED flags
360+
// copyClassDef(tree)(mods = mods | INTERFACE, impl = ifaceTemplate(impl))
358361
case DefDef(_,_,_,_,_,_) if sym.isClassConstructor && sym.isPrimaryConstructor && sym.owner != ArrayClass =>
359362
deriveDefDef(tree)(addMixinConstructorCalls(_, sym.owner)) // (3)
360363
case Template(parents, self, body) =>
361364
val parents1 = sym.owner.info.parents map (t => TypeTree(t) setPos tree.pos)
362365
treeCopy.Template(tree, parents1, noSelfType, body)
363-
case This(_) if sym.needsImplClass =>
364-
val impl = implClass(sym)
365-
var owner = currentOwner
366-
while (owner != sym && owner != impl) owner = owner.owner;
367-
if (owner == impl) This(impl) setPos tree.pos
368-
else tree
369-
//TODO what about this commented out code?
370-
/* !!!
371-
case Super(qual, mix) =>
372-
val mix1 = mix
373-
if (mix == tpnme.EMPTY) mix
374-
else {
375-
val ps = enteringErasure {
376-
sym.info.parents dropWhile (p => p.symbol.name != mix)
377-
}
378-
assert(!ps.isEmpty, tree);
379-
if (ps.head.symbol.needsImplClass) implClass(ps.head.symbol).name
380-
else mix
381-
}
382-
if (sym.needsImplClass) Super(implClass(sym), mix1) setPos tree.pos
383-
else treeCopy.Super(tree, qual, mix1)
384-
*/
366+
// case This(_) if sym.needsImplClass =>
367+
// val impl = implClass(sym)
368+
// var owner = currentOwner
369+
// while (owner != sym && owner != impl) owner = owner.owner;
370+
// if (owner == impl) This(impl) setPos tree.pos
371+
// else tree
372+
// //TODO what about this commented out code?
373+
///* !!!
374+
// case Super(qual, mix) =>
375+
// val mix1 = mix
376+
// if (mix == tpnme.EMPTY) mix
377+
// else {
378+
// val ps = enteringErasure {
379+
// sym.info.parents dropWhile (p => p.symbol.name != mix)
380+
// }
381+
// assert(!ps.isEmpty, tree);
382+
// if (ps.head.symbol.needsImplClass) implClass(ps.head.symbol).name
383+
// else mix
384+
// }
385+
// if (sym.needsImplClass) Super(implClass(sym), mix1) setPos tree.pos
386+
// else treeCopy.Super(tree, qual, mix1)
387+
//*/
385388
case _ =>
386389
tree
387390
}

src/reflect/scala/reflect/internal/HasFlags.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ trait HasFlags {
9999
def isFinal = hasFlag(FINAL)
100100
def isArtifact = hasFlag(ARTIFACT)
101101
def isImplicit = hasFlag(IMPLICIT)
102-
def isInterface = hasFlag(INTERFACE)
102+
def isInterface = hasFlag(INTERFACE) || isTrait
103103
def isJavaDefined = hasFlag(JAVA)
104104
def isLabel = hasAllFlags(LABEL | METHOD) && !hasAccessorFlag
105105
def isLazy = hasFlag(LAZY)

0 commit comments

Comments
 (0)