aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/transform/Erasure.scala
diff options
context:
space:
mode:
authorDmitry Petrashko <dmitry.petrashko@gmail.com>2014-04-01 23:27:54 +0200
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-04-04 18:59:25 +0200
commit0b50b29cb9e8b43fff1d012dd53561b5ac0a437c (patch)
tree1682ba5c7df18c9c246d129689bb8db02c94a625 /src/dotty/tools/dotc/transform/Erasure.scala
parent2033b5607a41b77590b8d23bf5c40c906a0b42e7 (diff)
downloaddotty-0b50b29cb9e8b43fff1d012dd53561b5ac0a437c.tar.gz
dotty-0b50b29cb9e8b43fff1d012dd53561b5ac0a437c.tar.bz2
dotty-0b50b29cb9e8b43fff1d012dd53561b5ac0a437c.zip
Bridge generation in erasure implemented.
Relies on meaning of "override" to see which bridges are required. Doesn't take in account value classes for now Uses 'adapt' used by erasure for converting arguments and return value.
Diffstat (limited to 'src/dotty/tools/dotc/transform/Erasure.scala')
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala97
1 files changed, 91 insertions, 6 deletions
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index d4156e1d7..1f618b9f6 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -18,8 +18,10 @@ import typer.ProtoTypes._
import typer.ErrorReporting._
import core.transform.Erasure._
import core.Decorators._
-import ast.{tpd, untpd}
+import dotty.tools.dotc.ast.{Trees, tpd, untpd}
import ast.Trees._
+import scala.collection.mutable.ListBuffer
+import dotty.tools.dotc.core.Flags
class Erasure extends Phase with DenotTransformer {
@@ -257,12 +259,95 @@ object Erasure {
override def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context) =
EmptyTree
- /*
- override def transformStats(stats: List[Tree], exprOwner: Symbol)(implicit ctx: Context) = {
- val stats1 = super.transform(stats, exprOwner)
- if (ctx.owner.isClass) addBridges(stats1) else stats1
+ override def typedStats(stats: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[tpd.Tree] = {
+ val statsFlatten = Trees.flatten(stats)
+ val stats1 = super.typedStats(statsFlatten, exprOwner)
+
+ if (ctx.owner.isClass) addBridges(statsFlatten, stats1)(ctx) else stats1
+ }
+
+ // this implementation doesn't check for bridge clashes with value types!
+ def addBridges(oldStats: List[untpd.Tree], newStats: List[tpd.Tree])(implicit ctx: Context): List[tpd.Tree] = {
+ val beforeCtx = ctx.withPhase(ctx.erasurePhase)
+ def traverse(after: List[Tree], before: List[untpd.Tree],
+ emittedBridges: ListBuffer[tpd.DefDef] = ListBuffer[tpd.DefDef]()): List[tpd.DefDef] = {
+ after match {
+ case Nil => emittedBridges.toList
+ case (member: DefDef) :: newTail =>
+ before match {
+ case Nil => emittedBridges.toList
+ case (oldMember: untpd.DefDef) :: oldTail =>
+ val oldSymbol = oldMember.symbol(beforeCtx)
+ val newSymbol = member.symbol(ctx)
+ assert(oldSymbol.name(beforeCtx) == newSymbol.name,
+ s"${oldSymbol.name(beforeCtx)} bridging with ${newSymbol.name}")
+ val newOverriden = oldSymbol.denot.allOverriddenSymbols.toSet
+ val oldOverriden = newSymbol.allOverriddenSymbols(beforeCtx).toSet
+ val neededBridges = oldOverriden -- newOverriden
+
+ var minimalSet = Set[Symbol]()
+ // compute minimal set of bridges that are needed:
+ for (bridge <- neededBridges) {
+ val isRequired = minimalSet.forall(nxtBridge => !(bridge.info =:= nxtBridge.info))
+
+ if (isRequired) {
+ // check for clashes
+ val clash: Option[Symbol] = oldSymbol.owner.decls.lookupAll(bridge.name).find {
+ sym =>
+ (sym.name eq bridge.name) && sym.info.widen =:= bridge.info.widen
+ }.orElse(
+ emittedBridges.find(stat => (stat.name == bridge.name) && stat.tpe.widen =:= bridge.info.widen)
+ .map(_.symbol)
+ )
+ clash match {
+ case Some(cl) =>
+ ctx.error(s"bridge for method ${newSymbol.show(beforeCtx)}\n" +
+ s"clashes with ${cl.symbol.show(beforeCtx)}\n" +
+ s"both have same type after erasure: ${bridge.symbol.info.show}")
+ case None => minimalSet += bridge
+ }
+ }
+ }
+
+ val bridgeImplementations = minimalSet.map {
+ sym => makeBridgeDef(member, sym)(ctx)
+ }
+ emittedBridges ++= bridgeImplementations
+ traverse(newTail, oldTail)
+ case notADefDef :: oldTail =>
+ traverse(after, oldTail)
+ }
+ case notADefDef :: newTail =>
+ traverse(newTail, before)
+ }
+ }
+
+ traverse(newStats, oldStats)
+ }
+
+ def makeBridgeDef(newDef: tpd.DefDef, parentSym: Symbol)(implicit ctx: Context): tpd.DefDef = {
+ def error(reason: String) = {
+ assert(false, s"failure creating bridge from ${newDef.symbol} to ${parentSym}, reason: $reason")
+ ???
+ }
+ val bridge = ctx.newSymbol(newDef.symbol.owner,
+ parentSym.name, parentSym.flags | Flags.Bridge, parentSym.info, coord = newDef.symbol.owner.coord).asTerm
+ bridge.entered // this should be safe, as we're executing in context of next phase
+ ctx.debuglog(s"generating bridge from ${newDef.symbol} to $bridge")
+
+ val sel: Tree = tpd.Select(This(newDef.symbol.owner.asClass), newDef.symbol.termRef)
+
+ val resultType = bridge.info.widen.resultType
+ tpd.DefDef(bridge, { paramss: List[List[tpd.Tree]] =>
+ val rhs = paramss.foldLeft(sel)((fun, vparams) =>
+ fun.tpe.widen match {
+ case MethodType(names, types) => Apply(fun, (vparams, types).zipped.map(adapt))
+ case a => error(s"can not resolve apply type $a")
+
+ })
+ adapt(rhs, resultType)
+ })
}
-*/
override def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
ctx.traceIndented(i"adapting ${tree.showSummary}: ${tree.tpe} to $pt", show = true) {