Skip to content

Commit 6502ff5

Browse files
committed
Emit trait method bodies in statics
And use this as the target of the default methods or statically resolved super or $init calls. The call-site change is predicated on `-Yuse-trait-statics` as a stepping stone for experimentation / bootstrapping. I have performed this transformation in the backend, rather than trying to reflect this in the view from Scala symbols + ASTs. Once we commit to this change, we can remove the `lateInterfaces` bookkeeping from the backend, as we no long will need to add ancestor interfaces as direct parents to allow use of invokespecial for super calls. ``` > ;scalac sandbox/test.scala ; scala Test [info] Running scala.tools.nsc.MainGenericRunner -usejavacp Test T C [success] Total time: 2 s, completed 04/05/2016 11:07:13 AM > eval "javap -classpath . -c -private C".!! [info] ans: String = Compiled from "test.scala" [info] public class C implements T { [info] public C(); [info] Code: [info] 0: aload_0 [info] 1: invokespecial #14 // Method java/lang/Object."<init>":()V [info] 4: aload_0 [info] 5: invokespecial #17 // Method T.$init$:()V [info] 8: getstatic #23 // Field scala/Predef$.MODULE$:Lscala/Predef$; [info] 11: ldc #24 // String C [info] 13: invokevirtual #28 // Method scala/Predef$.println:(Ljava/lang/Object;)V [info] 16: aload_0 [info] 17: invokespecial #32 // Method T.foo:()I [info] 20: pop [info] 21: return [info] } > ;scalac -Yuse-trait-statics sandbox/test.scala ; scala Test [info] Running scala.tools.nsc.MainGenericRunner -usejavacp Test T C [success] Total time: 2 s, completed 04/05/2016 11:07:39 AM > eval "javap -classpath . -c -private C".!! [info] ans: String = Compiled from "test.scala" [info] public class C implements T { [info] public C(); [info] Code: [info] 0: aload_0 [info] 1: invokespecial #14 // Method java/lang/Object."<init>":()V [info] 4: aload_0 [info] 5: invokestatic #18 // Method T.$init$:(LT;)V [info] 8: getstatic #24 // Field scala/Predef$.MODULE$:Lscala/Predef$; [info] 11: ldc #25 // String C [info] 13: invokevirtual #29 // Method scala/Predef$.println:(Ljava/lang/Object;)V [info] 16: aload_0 [info] 17: invokestatic #33 // Method T.foo:(LT;)I [info] 20: pop [info] 21: return [info] } > eval "javap -classpath . -c -private T".!! [info] ans: String = Compiled from "test.scala" [info] public interface T { [info] public static int foo(T); [info] Code: [info] 0: iconst_0 [info] 1: ireturn [info] [info] public int foo(); [info] Code: [info] 0: aload_0 [info] 1: invokestatic #15 // Method foo:(LT;)I [info] 4: ireturn [info] [info] public static void $init$(T); [info] Code: [info] 0: getstatic #24 // Field scala/Predef$.MODULE$:Lscala/Predef$; [info] 3: ldc #25 // String T [info] 5: invokevirtual #29 // Method scala/Predef$.println:(Ljava/lang/Object;)V [info] 8: return [info] [info] public void $init$(); [info] Code: [info] 0: aload_0 [info] 1: invokestatic #32 // Method $init$:(LT;)V [info] 4: return [info] } ```
1 parent 30e0985 commit 6502ff5

File tree

4 files changed

+20
-4
lines changed

4 files changed

+20
-4
lines changed

project/ScalaOptionParser.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ object ScalaOptionParser {
9090
"-Ypresentation-strict", "-Ypresentation-verbose", "-Yquasiquote-debug", "-Yrangepos", "-Yreify-copypaste", "-Yreify-debug", "-Yrepl-class-based",
9191
"-Yrepl-sync", "-Yshow-member-pos", "-Yshow-symkinds", "-Yshow-symowners", "-Yshow-syms", "-Yshow-trees", "-Yshow-trees-compact", "-Yshow-trees-stringified", "-Ytyper-debug",
9292
"-Ywarn-adapted-args", "-Ywarn-dead-code", "-Ywarn-inaccessible", "-Ywarn-infer-any", "-Ywarn-nullary-override", "-Ywarn-nullary-unit", "-Ywarn-numeric-widen", "-Ywarn-unused", "-Ywarn-unused-import", "-Ywarn-value-discard",
93-
"-deprecation", "-explaintypes", "-feature", "-help", "-no-specialization", "-nobootcp", "-nowarn", "-optimise", "-print", "-unchecked", "-uniqid", "-usejavacp", "-usemanifestcp", "-verbose", "-version")
93+
"-deprecation", "-explaintypes", "-feature", "-help", "-no-specialization", "-nobootcp", "-nowarn", "-optimise", "-print", "-unchecked", "-uniqid", "-usejavacp", "-usemanifestcp", "-verbose", "-version", "-Yuse-trait-statics")
9494
private def stringSettingNames = List("-Xgenerate-phase-graph", "-Xmain-class", "-Xpluginsdir", "-Xshow-class", "-Xshow-object", "-Xsource-reader", "-Ydump-classes", "-Ygen-asmp",
9595
"-Ypresentation-log", "-Ypresentation-replay", "-Yrepl-outdir", "-d", "-dependencyfile", "-encoding", "-Xscript")
9696
private def pathSettingNames = List("-bootclasspath", "-classpath", "-extdirs", "-javabootclasspath", "-javaextdirs", "-sourcepath", "-toolcp")

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
10611061
val receiverName = internalName(receiverClass)
10621062

10631063
// super calls are only allowed to direct parents
1064-
if (style.isSuper && receiverClass.isTraitOrInterface && !cnode.interfaces.contains(receiverName)) {
1064+
if (!settings.YuseTraitStatics.value && style.isSuper && receiverClass.isTraitOrInterface && !cnode.interfaces.contains(receiverName)) {
10651065
thisBType.info.get.inlineInfo.lateInterfaces += receiverName
10661066
cnode.interfaces.add(receiverName)
10671067
}
@@ -1082,7 +1082,11 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
10821082
case Virtual =>
10831083
if (needsInterfaceCall(receiverClass)) bc.invokeinterface(receiverName, jname, mdescr, pos)
10841084
else bc.invokevirtual (receiverName, jname, mdescr, pos)
1085-
case Super => bc.invokespecial (receiverName, jname, mdescr, pos)
1085+
case Super =>
1086+
if (receiverClass.isTraitOrInterface && settings.YuseTraitStatics.value) {
1087+
val staticDesc = MethodBType(typeToBType(method.owner.info) :: method.info.paramTypes.map(typeToBType), typeToBType(method.info.resultType)).descriptor
1088+
bc.invokestatic(receiverName, jname, staticDesc, pos)
1089+
} else bc.invokespecial (receiverName, jname, mdescr, pos)
10861090
}
10871091

10881092
bmType.returnType

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

+12-1
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,18 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
489489

490490
case ValDef(mods, name, tpt, rhs) => () // fields are added in `genPlainClass()`, via `addClassFields()`
491491

492-
case dd : DefDef => genDefDef(dd)
492+
case dd : DefDef =>
493+
if (dd.symbol.owner.isTrait && dd.rhs != EmptyTree && !dd.symbol.isPrivate && !dd.symbol.hasFlag(Flags.STATIC)) {
494+
// Split concrete methods in traits (including mixin constructors) into a static method
495+
// with an explicit this parameter, and a non-static forwarder method.
496+
val staticDefDef = global.gen.mkStatic(dd, _.cloneSymbol)
497+
val forwarderDefDef = {
498+
val forwarderBody = Apply(global.gen.mkAttributedRef(staticDefDef.symbol), This(dd.symbol.owner).setType(dd.symbol.owner.info) :: dd.vparamss.head.map(p => global.gen.mkAttributedIdent(p.symbol))).setType(dd.symbol.info.resultType)
499+
deriveDefDef(dd)(_ => global.atPos(dd.pos)(forwarderBody))
500+
}
501+
genDefDef(staticDefDef)
502+
genDefDef(forwarderDefDef)
503+
} else genDefDef(dd)
493504

494505
case Template(_, _, body) => body foreach gen
495506

src/compiler/scala/tools/nsc/settings/ScalaSettings.scala

+1
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ trait ScalaSettings extends AbsScalaSettings
201201
val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212)
202202
val inferByName = BooleanSetting ("-Yinfer-by-name", "Allow inference of by-name types. This is a temporary option to ease transition. See SI-7899.").withDeprecationMessage(removalIn212)
203203
val YdisableFlatCpCaching = BooleanSetting ("-YdisableFlatCpCaching", "Do not cache flat classpath representation of classpath elements from jars across compiler instances.")
204+
val YuseTraitStatics = BooleanSetting ("-Yuse-trait-statics", "Emit super calls to trait methods with invokestatic")
204205

205206
val exposeEmptyPackage = BooleanSetting ("-Yexpose-empty-package", "Internal only: expose the empty package.").internalOnly()
206207
val Ydelambdafy = ChoiceSetting ("-Ydelambdafy", "strategy", "Strategy used for translating lambdas into JVM code.", List("inline", "method"), "method")

0 commit comments

Comments
 (0)