Skip to content

Commit

Permalink
Don't move stats in constructor
Browse files Browse the repository at this point in the history
This is the best we can do with the current encoding of traits.
The problem can be seen from the following example:

trait A { def foo() = ??? }
trait B { def foo() = ??? }

object C extends A with B {
	super[A].foo()
	super[B].foo()
}

In the code above, we cannot translate the following calls
from <init> to <clinit>:

  super[A].foo()
  super[B].foo()

  super[A].$iinit$()
  super[B].$init$()

More details can be found here: #5928
  • Loading branch information
liufengyun committed Jul 10, 2020
1 parent 2c29afe commit c86ca4d
Showing 1 changed file with 27 additions and 26 deletions.
53 changes: 27 additions & 26 deletions compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ trait BCodeSkelBuilder extends BCodeHelpers {

val (clinits, body) = impl.body.partition(stat => stat.isInstanceOf[DefDef] && stat.symbol.isStaticConstructor)

val (uptoSuperStats, remainingConstrStats) = splitAtSuper(impl.constr.rhs.asInstanceOf[Block].stats)
val clInitSymbol: TermSymbol =
if (clinits.nonEmpty) clinits.head.symbol.asTerm
else ctx.newSymbol(
Expand All @@ -150,40 +149,42 @@ trait BCodeSkelBuilder extends BCodeHelpers {
coord = claszSymbol.coord
).entered

val thisMap = new TreeMap {
override def transform(tree: Tree)(using Context) = {
val tp = tree.tpe.substThis(claszSymbol.asClass, claszSymbol.sourceModule.termRef)
tree.withType(tp) match {
case tree: This if tree.symbol == claszSymbol =>
ref(claszSymbol.sourceModule)
case Apply(fun @ Select(Super(qual, _), _), args) if qual.symbol == claszSymbol =>
ref(claszSymbol.sourceModule).select(fun.symbol).appliedToArgs(args)
// case ident: Ident =>
// super.transform(desugarIdent(ident))
case tree =>
super.transform(tree)
}
}
}

def rewire(stat: Tree) = thisMap.transform(stat).changeOwner(claszSymbol.primaryConstructor, clInitSymbol)
// val thisMap = new TreeMap {
// override def transform(tree: Tree)(using Context) = {
// val tp = tree.tpe.substThis(claszSymbol.asClass, claszSymbol.sourceModule.termRef)
// tree.withType(tp) match {
// case tree: This if tree.symbol == claszSymbol =>
// ref(claszSymbol.sourceModule)
// case Apply(fun @ Select(Super(qual, mix), _), args) if qual.symbol == claszSymbol =>
// ref(claszSymbol.sourceModule).select(fun.symbol).appliedToArgs(args)
// case ident: Ident =>
// super.transform(desugarIdent(ident))
// case tree =>
// super.transform(tree)
// }
// }
// }

// def rewire(stat: Tree) = thisMap.transform(stat).changeOwner(claszSymbol.primaryConstructor, clInitSymbol)

// val (uptoSuperStats, remainingConstrStats) = splitAtSuper(impl.constr.rhs.asInstanceOf[Block].stats)
// val remainingConstrStatsSubst = remainingConstrStats.map(rewire)

val callConstructor = New(claszSymbol.typeRef).select(claszSymbol.primaryConstructor).appliedToArgs(Nil)
val assignModuleField = Assign(ref(moduleField), callConstructor)
val remainingConstrStatsSubst = remainingConstrStats.map(rewire)
val clinit = clinits match {
case (ddef: DefDef) :: _ =>
cpy.DefDef(ddef)(rhs = Block(ddef.rhs :: assignModuleField :: remainingConstrStatsSubst, unitLiteral))
cpy.DefDef(ddef)(rhs = Block(ddef.rhs :: assignModuleField :: Nil, unitLiteral))
case _ =>
DefDef(clInitSymbol, Block(assignModuleField :: remainingConstrStatsSubst, unitLiteral))
DefDef(clInitSymbol, Block(assignModuleField :: Nil, unitLiteral))
}

val constr2 = {
val rhs = Block(uptoSuperStats, impl.constr.rhs.asInstanceOf[Block].expr)
cpy.DefDef(impl.constr)(rhs = rhs)
}
// val constr2 = {
// val rhs = Block(uptoSuperStats, impl.constr.rhs.asInstanceOf[Block].expr)
// cpy.DefDef(impl.constr)(rhs = rhs)
// }

val impl2 = cpy.Template(impl)(constr = constr2, body = clinit :: body)
val impl2 = cpy.Template(impl)(body = clinit :: body)
cpy.TypeDef(cd0)(rhs = impl2)
} else cd0

Expand Down

0 comments on commit c86ca4d

Please sign in to comment.