@@ -14,9 +14,9 @@ import dotty.tools.dotc.CompilationUnit
14
14
import dotty .tools .dotc .core .Annotations .Annotation
15
15
import dotty .tools .dotc .core .Decorators ._
16
16
import dotty .tools .dotc .core .Flags ._
17
- import dotty .tools .dotc .core .StdNames .str
17
+ import dotty .tools .dotc .core .StdNames .{ nme , str }
18
18
import dotty .tools .dotc .core .Symbols ._
19
- import dotty .tools .dotc .core .Types .Type
19
+ import dotty .tools .dotc .core .Types .{ MethodType , Type }
20
20
import dotty .tools .dotc .util .Spans ._
21
21
import dotty .tools .dotc .report
22
22
@@ -496,7 +496,23 @@ trait BCodeSkelBuilder extends BCodeHelpers {
496
496
497
497
case ValDef (name, tpt, rhs) => () // fields are added in `genPlainClass()`, via `addClassFields()`
498
498
499
- case dd : DefDef => genDefDef(dd)
499
+ case dd : DefDef =>
500
+ /* First generate a static forwarder if this is a non-private trait
501
+ * trait method. This is required for super calls to this method, which
502
+ * go through the static forwarder in order to work around limitations
503
+ * of the JVM.
504
+ * In theory, this would go in a separate MiniPhase, but it would have to
505
+ * sit in a MegaPhase of its own between GenSJSIR and GenBCode, so the cost
506
+ * is not worth it. We directly do it in this back-end instead, which also
507
+ * kind of makes sense because it is JVM-specific.
508
+ */
509
+ val sym = dd.symbol
510
+ val needsStaticImplMethod =
511
+ claszSymbol.isInterface && ! dd.rhs.isEmpty && ! sym.isPrivate && ! sym.isStaticMember
512
+ if needsStaticImplMethod then
513
+ genStaticForwarderForDefDef(dd)
514
+
515
+ genDefDef(dd)
500
516
501
517
case tree : Template =>
502
518
val body =
@@ -537,6 +553,37 @@ trait BCodeSkelBuilder extends BCodeHelpers {
537
553
538
554
} // end of method initJMethod
539
555
556
+ private def genStaticForwarderForDefDef (dd : DefDef ): Unit =
557
+ val forwarderDef = makeStaticForwarder(dd)
558
+ genDefDef(forwarderDef)
559
+
560
+ /* Generates a synthetic static forwarder for a trait method.
561
+ * For a method such as
562
+ * def foo(...args: Ts): R
563
+ * in trait X, we generate the following method:
564
+ * static def foo$($this: X, ...args: Ts): R =
565
+ * invokespecial $this.X::foo(...args)
566
+ * We force an invokespecial with the attachment UseInvokeSpecial. It is
567
+ * necessary to make sure that the call will not follow overrides of foo()
568
+ * in subtraits and subclasses, since the whole point of this forward is to
569
+ * encode super calls.
570
+ */
571
+ private def makeStaticForwarder (dd : DefDef ): DefDef =
572
+ val origSym = dd.symbol.asTerm
573
+ val name = traitSuperAccessorName(origSym)
574
+ val info = origSym.info match
575
+ case mt : MethodType =>
576
+ MethodType (nme.SELF :: mt.paramNames, origSym.owner.typeRef :: mt.paramInfos, mt.resType)
577
+ val sym = origSym.copy(
578
+ name = name.toTermName,
579
+ flags = Method | JavaStatic ,
580
+ info = info
581
+ )
582
+ tpd.DefDef (sym.asTerm, { paramss =>
583
+ val params = paramss.head
584
+ tpd.Apply (params.head.select(origSym), params.tail)
585
+ .withAttachment(BCodeHelpers .UseInvokeSpecial , ())
586
+ })
540
587
541
588
def genDefDef (dd : DefDef ): Unit = {
542
589
val rhs = dd.rhs
0 commit comments