@@ -17,6 +17,7 @@ import dotty.tools.dotc.core.Decorators._
1717import dotty .tools .dotc .core .Flags ._
1818import dotty .tools .dotc .core .StdNames ._
1919import dotty .tools .dotc .core .NameKinds ._
20+ import dotty .tools .dotc .core .Names .TermName
2021import dotty .tools .dotc .core .Symbols ._
2122import dotty .tools .dotc .core .Types ._
2223import dotty .tools .dotc .core .Contexts ._
@@ -577,6 +578,13 @@ trait BCodeSkelBuilder extends BCodeHelpers {
577578 * trait method. This is required for super calls to this method, which
578579 * go through the static forwarder in order to work around limitations
579580 * 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+ *
580588 * In theory, this would go in a separate MiniPhase, but it would have to
581589 * sit in a MegaPhase of its own between GenSJSIR and GenBCode, so the cost
582590 * is not worth it. We directly do it in this back-end instead, which also
@@ -586,9 +594,13 @@ trait BCodeSkelBuilder extends BCodeHelpers {
586594 val needsStaticImplMethod =
587595 claszSymbol.isInterface && ! dd.rhs.isEmpty && ! sym.isPrivate && ! sym.isStaticMember
588596 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)
592604
593605 case tree : Template =>
594606 val body =
@@ -629,6 +641,42 @@ trait BCodeSkelBuilder extends BCodeHelpers {
629641
630642 } // end of method initJMethod
631643
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+
632680 private def genStaticForwarderForDefDef (dd : DefDef ): Unit =
633681 val forwarderDef = makeStaticForwarder(dd)
634682 genDefDef(forwarderDef)
@@ -646,20 +694,23 @@ trait BCodeSkelBuilder extends BCodeHelpers {
646694 */
647695 private def makeStaticForwarder (dd : DefDef ): DefDef =
648696 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 =
650706 val info = origSym.info match
651707 case mt : MethodType =>
652708 MethodType (nme.SELF :: mt.paramNames, origSym.owner.typeRef :: mt.paramInfos, mt.resType)
653- val sym = origSym.copy(
709+ origSym.copy(
654710 name = name.toTermName,
655711 flags = Method | JavaStatic ,
656712 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
663714
664715 def genDefDef (dd : DefDef ): Unit = {
665716 val rhs = dd.rhs
0 commit comments