Skip to content

Commit 35d9123

Browse files
committed
Re-enable trait forwarders
``` cat sandbox/test1.scala && javap -c -classpath . T C trait T { def m = 42 } class C extends T object Test { def main(args: Array[String]): Unit = { val c = new C() assert(c.m == 42) } } Compiled from "test1.scala" public interface T { public int m(); Code: 0: bipush 42 2: ireturn public void $init$(); Code: 0: return } Compiled from "test1.scala" public class C implements T { public int m(); Code: 0: aload_0 1: invokespecial #14 // Method T.m:()I 4: ireturn public C(); Code: 0: aload_0 1: invokespecial #20 // Method java/lang/Object."<init>":()V 4: aload_0 5: invokespecial #23 // Method T.$init$:()V 8: return } ``` Here's another test that shows private methods working: ``` cat sandbox/test3.scala && qscalac sandbox/test3.scala && javap -private -classpath . -c T C && qscala Test trait T { private def foo = 0 def bar = foo } class C extends T object Test { def main(args: Array[String]): Unit = { new C().bar } } Compiled from "test3.scala" public interface T { private int foo(); Code: 0: iconst_0 1: ireturn public int bar(); Code: 0: aload_0 1: invokespecial #15 // Method foo:()I 4: ireturn public void $init$(); Code: 0: return } Compiled from "test3.scala" public class C implements T { public int bar(); Code: 0: aload_0 1: invokespecial #14 // Method T.bar:()I 4: ireturn public C(); Code: 0: aload_0 1: invokespecial #20 // Method java/lang/Object."<init>":()V 4: aload_0 5: invokespecial #23 // Method T.$init$:()V 8: return } ```
1 parent e27c416 commit 35d9123

File tree

2 files changed

+12
-60
lines changed

2 files changed

+12
-60
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
4040
/** Is given trait member symbol a member of the trait's interface
4141
* after this transform is performed?
4242
*/
43-
private def isInterfaceMember(sym: Symbol) = (
43+
def isInterfaceMember(sym: Symbol) = (
4444
sym.isType || {
4545
sym.info // initialize to set lateMETHOD flag if necessary
4646

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

Lines changed: 11 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
4343
* methods in the impl class (because they can have arbitrary initializers)
4444
*/
4545
private def isImplementedStatically(sym: Symbol) = (
46-
sym.owner.isImplClass
46+
erasure.isInterfaceMember(sym)
47+
&& erasure.needsImplMethod(sym)
48+
&& sym.owner.isTrait
4749
&& sym.isMethod
4850
&& (!sym.isModule || sym.hasFlag(PRIVATE | LIFTED))
4951
&& (!(sym hasFlag (ACCESSOR | SUPERACCESSOR)) || (sym hasFlag LAZY | PARAMACCESSOR) || !(sym hasFlag SYNTHESIZE_IMPL_IN_SUBCLASS))
@@ -266,16 +268,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
266268
)
267269

268270
/* Mix in members of implementation class mixinClass into class clazz */
269-
def mixinImplClassMembers(mixinClass: Symbol, mixinInterface: Symbol) {
270-
if (!mixinClass.isImplClass) devWarning ("Impl class flag is not set " +
271-
((mixinClass.debugLocationString, mixinInterface.debugLocationString)))
272-
271+
def mixinTraitForwarders(mixinClass: Symbol) {
273272
for (member <- mixinClass.info.decls ; if isForwarded(member)) {
274-
val imember = member overriddenSymbol mixinInterface
275-
imember overridingSymbol clazz match {
273+
member overridingSymbol clazz match {
276274
case NoSymbol =>
277-
if (clazz.info.findMember(member.name, 0, lateDEFERRED, stableOnly = false).alternatives contains imember)
278-
cloneAndAddMixinMember(mixinInterface, imember).asInstanceOf[TermSymbol] setAlias member
275+
if (clazz.info.findMember(member.name, 0, 0L, stableOnly = false).alternatives contains member)
276+
cloneAndAddMixinMember(mixinClass, member).asInstanceOf[TermSymbol] setAlias member
279277
case _ =>
280278
}
281279
}
@@ -358,12 +356,12 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
358356
// first complete the superclass with mixed in members
359357
addMixedinMembers(clazz.superClass, unit)
360358

361-
for (mc <- clazz.mixinClasses ; if mc hasFlag lateINTERFACE) {
359+
for (mc <- clazz.mixinClasses ; if mc.isTrait) {
362360
// @SEAN: adding trait tracking so we don't have to recompile transitive closures
363361
unit.depends += mc
364362
addLateInterfaceMembers(mc)
365363
mixinTraitMembers(mc)
366-
mixinImplClassMembers(implClass(mc), mc)
364+
mixinTraitForwarders(mc)
367365
}
368366
}
369367

@@ -372,53 +370,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
372370
* - Implementation classes become modules that inherit nothing
373371
* and that define all.
374372
*/
375-
override def transformInfo(sym: Symbol, tp: Type): Type = tp match {
376-
case ClassInfoType(parents, decls, clazz) =>
377-
var parents1 = parents
378-
var decls1 = decls
379-
if (!clazz.isPackageClass) {
380-
exitingMixin(clazz.owner.info)
381-
if (clazz.isImplClass) {
382-
clazz setFlag lateMODULE
383-
var sourceModule = clazz.owner.info.decls.lookup(sym.name.toTermName)
384-
if (sourceModule == NoSymbol) {
385-
sourceModule = (
386-
clazz.owner.newModuleSymbol(sym.name.toTermName, sym.pos, MODULE)
387-
setModuleClass sym.asInstanceOf[ClassSymbol]
388-
)
389-
clazz.owner.info.decls enter sourceModule
390-
}
391-
else {
392-
sourceModule setPos sym.pos
393-
if (sourceModule.flags != MODULE) {
394-
log(s"!!! Directly setting sourceModule flags for $sourceModule from ${sourceModule.flagString} to MODULE")
395-
sourceModule.flags = MODULE
396-
}
397-
}
398-
sourceModule setInfo sym.tpe
399-
// Companion module isn't visible for anonymous class at this point anyway
400-
assert(clazz.sourceModule != NoSymbol || clazz.isAnonymousClass, s"$clazz has no sourceModule: $sym ${sym.tpe}")
401-
parents1 = List()
402-
decls1 = newScopeWith(decls.toList filter isImplementedStatically: _*)
403-
} else if (!parents.isEmpty) {
404-
parents1 = parents.head :: (parents.tail map toInterface)
405-
}
406-
}
407-
//decls1 = enteringPhase(phase.next)(newScopeWith(decls1.toList: _*))//debug
408-
if ((parents1 eq parents) && (decls1 eq decls)) tp
409-
else ClassInfoType(parents1, decls1, clazz)
410-
411-
case MethodType(params, restp) =>
412-
toInterfaceMap(
413-
if (isImplementedStatically(sym)) {
414-
val ownerParam = sym.newSyntheticValueParam(toInterface(sym.owner.typeOfThis))
415-
MethodType(ownerParam :: params, restp)
416-
} else
417-
tp)
418-
419-
case _ =>
420-
tp
421-
}
373+
override def transformInfo(sym: Symbol, tp: Type): Type = tp
422374

423375
/** Return a map of single-use fields to the lazy value that uses them during initialization.
424376
* Each field has to be private and defined in the enclosing class, and there must
@@ -1108,7 +1060,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
11081060
val rhs =
11091061
enteringPickler(sym.info) match {
11101062
case ct: ConstantType => gen.mkAttributedQualifier(ct) // don't call forwarder if it's just going to return a literal (no need for this in the new trait encoding)
1111-
case _ => Apply(staticRef(sym.alias), gen.mkAttributedThis(clazz) :: sym.paramss.head.map(Ident))
1063+
case _ => Apply(Select(Super(clazz, tpnme.EMPTY), sym.alias), sym.paramss.head.map(Ident))
11121064
}
11131065
addDefDef(sym, rhs)
11141066
}

0 commit comments

Comments
 (0)