aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/transform/Mixin.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-11-08 09:45:30 +0100
committerMartin Odersky <odersky@gmail.com>2014-11-09 19:09:52 +0100
commitfea26e104d202f3ac755f309d982af4d7ddd7bba (patch)
treea921ae55d84c587784ddeb0bad7780e823ff68fc /src/dotty/tools/dotc/transform/Mixin.scala
parent0cd63ac2a8ae378d85922cbef4c3b4654fb75ea7 (diff)
downloaddotty-fea26e104d202f3ac755f309d982af4d7ddd7bba.tar.gz
dotty-fea26e104d202f3ac755f309d982af4d7ddd7bba.tar.bz2
dotty-fea26e104d202f3ac755f309d982af4d7ddd7bba.zip
New Mixin scheme.
Split into two phases, ResolveSuper before Erasure and Mixin after. Likewise GettersSetters is split into Getters and Memoize. All tests pass, except two tests fail when compiled twice. Will investigate next why.
Diffstat (limited to 'src/dotty/tools/dotc/transform/Mixin.scala')
-rw-r--r--src/dotty/tools/dotc/transform/Mixin.scala257
1 files changed, 91 insertions, 166 deletions
diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala
index 8116c723a..59bb8b910 100644
--- a/src/dotty/tools/dotc/transform/Mixin.scala
+++ b/src/dotty/tools/dotc/transform/Mixin.scala
@@ -14,19 +14,19 @@ import DenotTransformers._
import StdNames._
import NameOps._
import ast.Trees._
-import util.Positions._
import collection.mutable
+// todo: interface
/** This phase performs the following transformations:
*
- * 1. (done in `traitDefs`) Map every concrete trait field
+ * 1. (done in `traitDefs`) Map every concrete trait getter
*
- * <mods> val x: T = expr
+ * <mods> def x(): T = expr
*
* to the pair of definitions:
*
- * <mods> val x: T
- * protected def initial$x: T = { stats; expr }
+ * <mods> def x(): T
+ * protected def initial$x(): T = { stats; expr }
*
* where `stats` comprises all statements between either the start of the trait
* or the previous field definition which are not definitions (i.e. are executed for
@@ -45,33 +45,18 @@ import collection.mutable
* For every trait M directly implemented by the class (see SymUtils.mixin), in
* reverse linearization order, add the following definitions to C:
*
- * 3.1 (done in `traitInits`) For every concrete trait field `<mods> val x: T` in M,
+ * 3.1 (done in `traitInits`) For every concrete trait getter `<mods> def x(): T` in M,
* in order of textual occurrence:
*
- * <mods> val x: T = super[M].initial$x
+ * <mods> def x(): T = super[M].initial$x()
*
- * 3.2 (done in `constrCall`) The call:
+ * 3.2 (done in `superCallOpt`) The call:
*
* super[M].<init>
*
* 3.3 (done in `setters`) For every concrete setter `<mods> def x_=(y: T)` in M:
*
* <mods> def x_=(y: T) = ()
- *
- * 3.4 (done in `superAccessors`) For every superAccessor
- * `<mods> def super$f[Ts](ps1)...(psN): U` in M:
- *
- * <mods> def super$f[Ts](ps1)...(psN): U = super[S].f[Ts](ps1)...(psN)
- *
- * where `S` is the superclass of `M` in the linearization of `C`.
- *
- * 3.5 (done in `methodOverrides`) For every method
- * `<mods> def f[Ts](ps1)...(psN): U` in M` that needs to be disambiguated:
- *
- * <mods> def f[Ts](ps1)...(psN): U = super[M].f[Ts](ps1)...(psN)
- *
- * A method in M needs to be disambiguated if it is concrete, not overridden in C,
- * and if it overrides another concrete method.
*/
class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
import ast.tpd._
@@ -81,166 +66,106 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform =>
override def treeTransformPhase = thisTransform.next
override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation =
- if (sym is Trait) {
- lazy val newDecls = sym.decls.cloneScope
- var hasInit = false
- for (d <- sym.decls)
- if (d.isTerm && !d.is(MethodOrDeferred)) {
- hasInit = true
- val initializer = ctx.newSymbol(
- sym.symbol,
- InitializerName(d.asTerm.name),
- Protected | Synthetic | Method,
- ExprType(d.info),
- coord = d.coord)
- newDecls.enter(initializer)
- }
- if (hasInit) {
- val cinfo = sym.asClass.classInfo
- sym.copySymDenotation(info = cinfo.derivedClassInfo(decls = newDecls))
- }
- else sym
- }
- else if ((sym.isField || sym.isSetter) && sym.owner.is(Trait) && !sym.is(Deferred))
+ if (sym.is(Accessor, butNot = Deferred) && sym.owner.is(Trait))
sym.copySymDenotation(initFlags = sym.flags | Deferred)
else
sym
- private val MethodOrDeferred = Method | Deferred
- private val PrivateOrDeferred = Private | Deferred
-
- private def traitDefs(cls: ClassSymbol, stats: List[Tree])(implicit ctx: Context): List[Tree] = {
- val initBuf = new mutable.ListBuffer[Tree]
- stats flatMap {
- case stat: ValDef if !stat.rhs.isEmpty =>
- val vsym = stat.symbol
- val isym = vsym.initializer
- val rhs = Block(
- initBuf.toList,
- stat.rhs.changeOwner(vsym, isym).ensureConforms(isym.info.widen))
- initBuf.clear()
- List(
- cpy.ValDef(stat)(mods = stat.mods | Deferred, rhs = EmptyTree),
- DefDef(stat.symbol.initializer, rhs))
- case stat: DefDef if stat.symbol.isSetter =>
- List(cpy.DefDef(stat)(
- mods = stat.mods | Deferred,
- rhs = EmptyTree))
- case stat: DefTree =>
- List(stat)
- case stat =>
- initBuf += stat
- Nil
- }
+ private def initializer(sym: Symbol)(implicit ctx: Context): TermSymbol = {
+ val initName = InitializerName(sym.name.asTermName)
+ sym.owner.info.decl(initName).symbol
+ .orElse(
+ ctx.newSymbol(
+ sym.owner,
+ initName,
+ Protected | Synthetic | Method,
+ sym.info,
+ coord = sym.symbol.coord).enteredAfter(thisTransform))
+ .asTerm
}
- /** Returns the symbol that is accessed by a super-accessor in a mixin composition.
- *
- * @param base The class in which everything is mixed together
- * @param member The symbol statically referred to by the superaccessor in the trait
- */
- private def rebindSuper(base: Symbol, acc: Symbol)(implicit ctx: Context): Symbol = {
- var bcs = base.info.baseClasses.dropWhile(acc.owner != _).tail
- var sym: Symbol = NoSymbol
- val SuperAccessorName(memberName) = acc.name
- ctx.debuglog("starting rebindsuper " + base + " " + memberName + ":" + acc.info +
- " " + acc.owner + " " + base.info.baseClasses + "/" + bcs)
- while (!bcs.isEmpty && sym == NoSymbol) {
- val other = bcs.head.info.nonPrivateDecl(memberName)
- if (ctx.settings.debug.value)
- ctx.debuglog("rebindsuper " + bcs.head + " " + other + " " + other.info +
- " " + other.symbol.is(Deferred))
- sym = other.matchingDenotation(base.thisType, acc.info).symbol
- bcs = bcs.tail
+ override def transformTemplate(impl: Template)(implicit ctx: Context, info: TransformerInfo) = {
+ val cls = impl.symbol.owner.asClass
+ val ops = new MixinOps(cls, thisTransform)
+ import ops._
+
+ def traitDefs(stats: List[Tree]): List[Tree] = {
+ val initBuf = new mutable.ListBuffer[Tree]
+ stats flatMap {
+ case stat: DefDef if stat.symbol.isGetter && !stat.rhs.isEmpty =>
+ val vsym = stat.symbol
+ val isym = initializer(vsym)
+ val rhs = Block(
+ initBuf.toList.map(_.changeOwner(impl.symbol, isym)),
+ stat.rhs.changeOwner(vsym, isym))
+ initBuf.clear()
+ List(
+ cpy.DefDef(stat)(mods = stat.mods | Deferred, rhs = EmptyTree),
+ DefDef(isym, rhs))
+ case stat: DefDef if stat.symbol.isSetter =>
+ List(cpy.DefDef(stat)(
+ mods = stat.mods | Deferred,
+ rhs = EmptyTree))
+ case stat: DefTree =>
+ List(stat)
+ case stat =>
+ initBuf += stat
+ Nil
+ }
}
- sym
- }
-
- private def superAccessors(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] =
- for (superAcc <- mixin.decls.filter(_ is SuperAccessor).toList)
- yield polyDefDef(implementation(cls, superAcc.asTerm), forwarder(cls, rebindSuper(cls, superAcc)))
-
- private def traitInits(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] =
- for (field <- mixin.decls.filter(fld => fld.isField && !wasDeferred(fld)).toList)
- yield ValDef(implementation(cls, field.asTerm), superRef(cls, field.initializer, cls.pos))
- private def setters(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] =
- for (setter <- mixin.decls.filter(setr => setr.isSetter && !wasDeferred(setr)).toList)
- yield DefDef(implementation(cls, setter.asTerm), unitLiteral.withPos(cls.pos))
-
- private def implementation(cls: ClassSymbol, member: TermSymbol)(implicit ctx: Context): TermSymbol =
- member.copy(
- owner = cls,
- name = member.name.stripScala2LocalSuffix,
- flags = member.flags &~ Deferred).enteredAfter(thisTransform).asTerm
-
- private def methodOverrides(cls: ClassSymbol, mixin: ClassSymbol)(implicit ctx: Context): List[Tree] = {
- def isOverridden(meth: Symbol) = meth.overridingSymbol(cls).is(Method, butNot = Deferred)
- def needsDisambiguation(meth: Symbol): Boolean =
- meth.is(Method, butNot = PrivateOrDeferred) &&
- !isOverridden(meth) &&
- !meth.allOverriddenSymbols.forall(_ is Deferred)
- for (meth <- mixin.decls.toList if needsDisambiguation(meth))
- yield polyDefDef(implementation(cls, meth.asTerm), forwarder(cls, meth))
- }
-
- private def wasDeferred(sym: Symbol)(implicit ctx: Context) =
- ctx.atPhase(thisTransform) { implicit ctx => sym is Deferred }
+ def transformSuper(tree: Tree): Tree = {
+ val Apply(sel @ Select(New(_), nme.CONSTRUCTOR), args) = tree
+ superRef(tree.symbol, tree.pos).appliedToArgs(args)
+ }
- private def superRef(cls: ClassSymbol, target: Symbol, pos: Position)(implicit ctx: Context) = {
- val inTrait = target.owner is Trait
- Super(
- qual = This(cls),
- mix = if (inTrait) target.owner.name.asTypeName else tpnme.EMPTY,
- inConstrCall = target.isConstructor && !target.owner.is(Trait),
- mixinClass = if (inTrait) target.owner else NoSymbol
- ).select(target)
- }
+ val superCalls = (
+ for (p <- impl.parents if p.symbol.isConstructor)
+ yield p.symbol.owner -> transformSuper(p)
+ ).toMap
- private def forwarder(cls: ClassSymbol, target: Symbol)(implicit ctx: Context) =
- (targs: List[Type]) => (vrefss: List[List[Tree]]) =>
- superRef(cls, target, cls.pos).appliedToTypes(targs).appliedToArgss(vrefss)
+ def superCallOpt(baseCls: Symbol): List[Tree] = superCalls.get(baseCls) match {
+ case Some(call) =>
+ if (defn.PhantomClasses.contains(baseCls)) Nil else call :: Nil
+ case None =>
+ if (baseCls.is(Interface) || defn.PhantomClasses.contains(baseCls)) Nil
+ else {
+ //println(i"synth super call ${baseCls.primaryConstructor}: ${baseCls.primaryConstructor.info}")
+ superRef(baseCls.primaryConstructor).appliedToNone :: Nil
+/* constr.tpe.widen match {
+ case tpe: PolyType =>
+ val targs = cls.thisType.baseTypeWithArgs(baseCls).argTypes
+ constr = constr.appliedToTypes(targs)
+ case _ =>
+ }
+ constr.ensureApplied :: Nil
+*/
+ }
+ }
- override def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo) = {
- val cls = tree.symbol.owner.asClass
- val stats = tree.body
- val superCls = cls.classInfo.parents.head.symbol
- val mixins = cls.baseClasses.tail.takeWhile(_ ne superCls)
+ def wasDeferred(sym: Symbol) =
+ ctx.atPhase(thisTransform) { implicit ctx => sym is Deferred }
- // If parent is a constructor call, pull out the call into a separate
- // supercall constructor, which gets added to `superCalls`, and keep
- // only the type.
- val superCalls = new mutable.HashMap[Symbol, Tree]
- def normalizeParent(tree: Tree) = tree match {
- case superApp @ Apply(superSel @ Select(New(superType), nme.CONSTRUCTOR), superArgs) =>
- val constr = superSel.symbol
- superCalls(constr.owner) = superRef(cls, constr, superSel.pos).appliedToArgs(superArgs)
- superType
- case tree: TypeTree => tree
- }
- val parentTypeTrees = tree.parents.map(normalizeParent)
+ def traitInits(mixin: ClassSymbol): List[Tree] =
+ for (getter <- mixin.decls.filter(getr => getr.isGetter && !wasDeferred(getr)).toList)
+ yield {
+ println(i"impl for getter $getter!")
+ DefDef(implementation(getter.asTerm), superRef(initializer(getter)).appliedToNone)
+ }
- def supCalls(baseCls: Symbol): List[Tree] = superCalls.remove(baseCls) match {
- case Some(call) => call :: Nil
- case None =>
- if (baseCls is Interface) Nil
- else superRef(cls, baseCls.primaryConstructor, cls.pos).appliedToNone :: Nil
- }
+ def setters(mixin: ClassSymbol): List[Tree] =
+ for (setter <- mixin.decls.filter(setr => setr.isSetter && !wasDeferred(setr)).toList)
+ yield DefDef(implementation(setter.asTerm), unitLiteral.withPos(cls.pos))
- cpy.Template(tree)(
- parents = parentTypeTrees,
+ cpy.Template(impl)(
+ parents = impl.parents.map(p => TypeTree(p.tpe).withPos(p.pos)),
body =
- if (cls is Trait) traitDefs(cls, stats)
+ if (cls is Trait) traitDefs(impl.body)
else {
val mixInits = mixins.flatMap { mixin =>
- assert(mixin is Trait)
- traitInits(cls, mixin) :::
- supCalls(mixin) :::
- setters(cls, mixin) :::
- superAccessors(cls, mixin) :::
- methodOverrides(cls, mixin)
+ traitInits(mixin) ::: superCallOpt(mixin) ::: setters(mixin)
}
- supCalls(superCls) ::: mixInits ::: stats
+ superCallOpt(superCls) ::: mixInits ::: impl.body
})
}
-} \ No newline at end of file
+}