Skip to content

Commit 2766f86

Browse files
committed
WIP Emit concrete methods in traits as JDK8 default methods
``` cat sandbox/test.scala && qscalac -target:jvm-1.8 -Ybackend:GenASM sandbox/test.scala && (for c in 'T' 'T$' 'C'; do javap -c -classpath . $c; done) | cat -v; qscala Test trait T { def t(s: String) = 42 val v = 42 } class C extends T object Test { def main(args: Array[String]): Unit = { println(new C().t("")) } } Compiled from "test.scala" public interface T { public abstract void T$_setter_$v_$eq(int); public int t(java.lang.String); Code: 0: bipush 42 2: ireturn public abstract int v(); } Error: class not found: T$ Compiled from "test.scala" public class C implements T { public int v(); Code: 0: aload_0 1: getfield #15 // Field v:I 4: ireturn public void T$_setter_$v_$eq(int); Code: 0: aload_0 1: iload_1 2: putfield #15 // Field v:I 5: return public C(); Code: 0: aload_0 1: invokespecial #24 // Method java/lang/Object."<init>":()V 4: aload_0 5: invokestatic #30 // Method T$class.$init$:(LT;)V 8: return } 42 topic/indylambda-emit-indy /code/scala2 cat sandbox/test.scala && qscalac -target:jvm-1.8 -Ybackend:GenBCode sandbox/test.scala && (for c in 'T' 'T$' 'C'; do javap -c -classpath . $c; done) | cat -v; qscala Test trait T { def t(s: String) = 42 val v = 42 } class C extends T object Test { def main(args: Array[String]): Unit = { println(new C().t("")) } } Compiled from "test.scala" public interface T { public abstract void T$_setter_$v_$eq(int); public int t(java.lang.String); Code: 0: bipush 42 2: ireturn public abstract int v(); } Error: class not found: T$ Compiled from "test.scala" public class C implements T { public int v(); Code: 0: aload_0 1: getfield #15 // Field v:I 4: ireturn public void T$_setter_$v_$eq(int); Code: 0: aload_0 1: iload_1 2: putfield #15 // Field v:I 5: return public C(); Code: 0: aload_0 1: invokespecial #24 // Method java/lang/Object."<init>":()V 4: aload_0 5: invokestatic #30 // Method T$class.$init$:(LT;)V 8: return } 42 ```
1 parent 3bf208f commit 2766f86

File tree

5 files changed

+21
-7
lines changed

5 files changed

+21
-7
lines changed

src/compiler/scala/tools/nsc/backend/icode/Members.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package backend
99
package icode
1010

1111
import scala.collection.{ mutable, immutable }
12+
import scala.reflect.internal.Flags
1213
import scala.reflect.internal.util.{ SourceFile, NoSourceFile }
1314

1415
trait ReferenceEquality {
@@ -217,7 +218,7 @@ trait Members {
217218

218219
/** Is this method deferred ('abstract' in Java sense)?
219220
*/
220-
def isAbstractMethod = symbol.isDeferred || symbol.owner.isInterface || native
221+
def isAbstractMethod = symbol.isDeferred || (symbol.owner.isInterface && !symbol.hasFlag(Flags.DEFAULTMETHOD)) || native
221222

222223
def isStatic: Boolean = symbol.isStaticMember
223224

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,10 +575,11 @@ abstract class BCodeSkelBuilder extends BCodeHelpers {
575575
}
576576

577577
val isNative = methSymbol.hasAnnotation(definitions.NativeAttr)
578-
val isAbstractMethod = (methSymbol.isDeferred || methSymbol.owner.isInterface)
578+
val isAbstractMethod = (methSymbol.isDeferred || (methSymbol.owner.isInterface && !methSymbol.hasFlag(Flags.DEFAULTMETHOD)))
579+
val isAbstract2 = claszSymbol.isInterface && !methSymbol.hasFlag(Flags.DEFAULTMETHOD)
579580
val flags = GenBCode.mkFlags(
580581
javaFlags(methSymbol),
581-
if (claszSymbol.isInterface) asm.Opcodes.ACC_ABSTRACT else 0,
582+
if (isAbstract2) asm.Opcodes.ACC_ABSTRACT else 0,
582583
if (methSymbol.isStrictFP) asm.Opcodes.ACC_STRICT else 0,
583584
if (isNative) asm.Opcodes.ACC_NATIVE else 0 // native methods of objects are generated in mirror classes
584585
)

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self =>
297297
// without having to provide any implementations, but that is an
298298
// illegal combination of modifiers at the bytecode level so
299299
// suppress final if abstract if present.
300+
300301
import asm.Opcodes._
301302
mkFlags(
302303
if (privateFlag) ACC_PRIVATE else ACC_PUBLIC,
@@ -1400,10 +1401,11 @@ abstract class GenASM extends SubComponent with BytecodeWriters { self =>
14001401
var resTpe: asm.Type = javaType(m.symbol.tpe.resultType)
14011402
if (m.symbol.isClassConstructor)
14021403
resTpe = asm.Type.VOID_TYPE
1404+
val isAbstractTraitMeth = isJInterface && !m.symbol.hasFlag(Flags.DEFAULTMETHOD)
14031405

14041406
val flags = mkFlags(
14051407
javaFlags(m.symbol),
1406-
if (isJInterface) asm.Opcodes.ACC_ABSTRACT else 0,
1408+
if (isAbstractTraitMeth) asm.Opcodes.ACC_ABSTRACT else 0,
14071409
if (m.symbol.isStrictFP) asm.Opcodes.ACC_STRICT else 0,
14081410
if (method.native) asm.Opcodes.ACC_NATIVE else 0, // native methods of objects are generated in mirror classes
14091411
if(isDeprecated(m.symbol)) asm.Opcodes.ACC_DEPRECATED else 0 // ASM pseudo access flag

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
5959
sym.isMethod
6060
&& isInterfaceMember(sym)
6161
&& (!sym.hasFlag(DEFERRED | SUPERACCESSOR) || (sym hasFlag lateDEFERRED))
62+
&& !useDefaultMethod(sym)
6263
)
6364

6465
def implClassPhase = currentRun.erasurePhase.next
@@ -246,9 +247,13 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
246247
val isInterfaceTree = tree.isDef && isInterfaceMember(tree.symbol)
247248
if (isInterfaceTree && needsImplMethod(tree.symbol))
248249
create(tree)
249-
else if (isInterfaceTree == isForInterface)
250+
else if (isInterfaceTree == isForInterface) {
251+
if (isInterfaceTree) {
252+
tree.symbol.resetFlag(lateDEFERRED)
253+
tree.symbol.setFlag(DEFAULTMETHOD)
254+
}
250255
tree
251-
else
256+
} else
252257
EmptyTree
253258
}
254259
private def implMemberDef(tree: Tree): Tree = createMemberDef(tree, false)(implMethodDef)
@@ -257,6 +262,11 @@ abstract class AddInterfaces extends InfoTransform { self: Erasure =>
257262
private def ifaceTemplate(templ: Template): Template =
258263
treeCopy.Template(templ, templ.parents, noSelfType, templ.body map ifaceMemberDef)
259264

265+
private def useDefaultMethod(methodSym: Symbol) = {
266+
val isJvm18 = settings.target.value == "jvm-1.8"
267+
val hasClassOwner = methodSym.allOverriddenSymbols.exists(_.owner.isClass)
268+
isJvm18 && !hasClassOwner && !methodSym.isModule && !(methodSym hasFlag (ACCESSOR | SUPERACCESSOR))
269+
}
260270
/** Transforms the member tree containing the implementation
261271
* into a member of the impl class.
262272
*/

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
528528
addLateInterfaceMembers(currentOwner)
529529

530530
tree
531-
case DefDef(_, _, _, vparams :: Nil, _, _) =>
531+
case dd @ DefDef(_, _, _, vparams :: Nil, _, _) =>
532532
if (currentOwner.isImplClass) {
533533
if (isImplementedStatically(sym)) {
534534
sym setFlag notOVERRIDE

0 commit comments

Comments
 (0)