@@ -17,6 +17,7 @@ import dotty.tools.dotc.core.Decorators._
17
17
import dotty .tools .dotc .core .Flags ._
18
18
import dotty .tools .dotc .core .StdNames ._
19
19
import dotty .tools .dotc .core .NameKinds ._
20
+ import dotty .tools .dotc .core .Names .TermName
20
21
import dotty .tools .dotc .core .Symbols ._
21
22
import dotty .tools .dotc .core .Types ._
22
23
import dotty .tools .dotc .core .Contexts ._
@@ -577,6 +578,13 @@ trait BCodeSkelBuilder extends BCodeHelpers {
577
578
* trait method. This is required for super calls to this method, which
578
579
* go through the static forwarder in order to work around limitations
579
580
* of the JVM.
581
+ *
582
+ * For the $init$ method, we must not leave it as a default method, but
583
+ * instead we must put the whole body in the static method. If we leave
584
+ * it as a default method, Java classes cannot extend Scala classes that
585
+ * extend several Scala traits, since they then inherit unrelated default
586
+ * $init$ methods. See #8599. scalac does the same thing.
587
+ *
580
588
* In theory, this would go in a separate MiniPhase, but it would have to
581
589
* sit in a MegaPhase of its own between GenSJSIR and GenBCode, so the cost
582
590
* is not worth it. We directly do it in this back-end instead, which also
@@ -586,9 +594,13 @@ trait BCodeSkelBuilder extends BCodeHelpers {
586
594
val needsStaticImplMethod =
587
595
claszSymbol.isInterface && ! dd.rhs.isEmpty && ! sym.isPrivate && ! sym.isStaticMember
588
596
if needsStaticImplMethod then
589
- genStaticForwarderForDefDef(dd)
590
-
591
- genDefDef(dd)
597
+ if sym.name == nme.TRAIT_CONSTRUCTOR then
598
+ genTraitConstructorDefDef(dd)
599
+ else
600
+ genStaticForwarderForDefDef(dd)
601
+ genDefDef(dd)
602
+ else
603
+ genDefDef(dd)
592
604
593
605
case tree : Template =>
594
606
val body =
@@ -629,6 +641,42 @@ trait BCodeSkelBuilder extends BCodeHelpers {
629
641
630
642
} // end of method initJMethod
631
643
644
+ private def genTraitConstructorDefDef (dd : DefDef ): Unit =
645
+ val statifiedDef = makeStatifiedDefDef(dd)
646
+ genDefDef(statifiedDef)
647
+
648
+ /** Creates a copy of the given DefDef that is static and where an explicit
649
+ * self parameter represents the original `this` value.
650
+ *
651
+ * Example: from
652
+ * {{{
653
+ * trait Enclosing {
654
+ * def foo(x: Int): String = this.toString() + x
655
+ * }
656
+ * }}}
657
+ * the statified version of `foo` would be
658
+ * {{{
659
+ * static def foo($self: Enclosing, x: Int): String = $self.toString() + x
660
+ * }}}
661
+ */
662
+ private def makeStatifiedDefDef (dd : DefDef ): DefDef =
663
+ val origSym = dd.symbol.asTerm
664
+ val newSym = makeStatifiedDefSymbol(origSym, origSym.name)
665
+ tpd.DefDef (newSym, { paramRefss =>
666
+ val selfParamRef :: regularParamRefs = paramRefss.head
667
+ val enclosingClass = origSym.owner.asClass
668
+ new TreeTypeMap (
669
+ typeMap = _.substThis(enclosingClass, selfParamRef.symbol.termRef)
670
+ .subst(dd.vparamss.head.map(_.symbol), regularParamRefs.map(_.symbol.termRef)),
671
+ treeMap = {
672
+ case tree : This if tree.symbol == enclosingClass => selfParamRef
673
+ case tree => tree
674
+ },
675
+ oldOwners = origSym :: Nil ,
676
+ newOwners = newSym :: Nil
677
+ ).transform(dd.rhs)
678
+ })
679
+
632
680
private def genStaticForwarderForDefDef (dd : DefDef ): Unit =
633
681
val forwarderDef = makeStaticForwarder(dd)
634
682
genDefDef(forwarderDef)
@@ -646,20 +694,23 @@ trait BCodeSkelBuilder extends BCodeHelpers {
646
694
*/
647
695
private def makeStaticForwarder (dd : DefDef ): DefDef =
648
696
val origSym = dd.symbol.asTerm
649
- val name = traitSuperAccessorName(origSym)
697
+ val name = traitSuperAccessorName(origSym).toTermName
698
+ val sym = makeStatifiedDefSymbol(origSym, name)
699
+ tpd.DefDef (sym, { paramss =>
700
+ val params = paramss.head
701
+ tpd.Apply (params.head.select(origSym), params.tail)
702
+ .withAttachment(BCodeHelpers .UseInvokeSpecial , ())
703
+ })
704
+
705
+ private def makeStatifiedDefSymbol (origSym : TermSymbol , name : TermName ): TermSymbol =
650
706
val info = origSym.info match
651
707
case mt : MethodType =>
652
708
MethodType (nme.SELF :: mt.paramNames, origSym.owner.typeRef :: mt.paramInfos, mt.resType)
653
- val sym = origSym.copy(
709
+ origSym.copy(
654
710
name = name.toTermName,
655
711
flags = Method | JavaStatic ,
656
712
info = info
657
- )
658
- tpd.DefDef (sym.asTerm, { paramss =>
659
- val params = paramss.head
660
- tpd.Apply (params.head.select(origSym), params.tail)
661
- .withAttachment(BCodeHelpers .UseInvokeSpecial , ())
662
- })
713
+ ).asTerm
663
714
664
715
def genDefDef (dd : DefDef ): Unit = {
665
716
val rhs = dd.rhs
0 commit comments