diff options
author | Martin Odersky <odersky@gmail.com> | 2014-09-21 15:03:29 +0200 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2014-10-11 08:24:36 +0200 |
commit | 96f754c92713d1a199b844fe5501dafaad45d7cb (patch) | |
tree | e926f1d2d664ab25163308143828261b3da5777d /src/dotty/tools/dotc/transform/Constructors.scala | |
parent | 330773619d01b9f684676ec4253b3d76c4807222 (diff) | |
download | dotty-96f754c92713d1a199b844fe5501dafaad45d7cb.tar.gz dotty-96f754c92713d1a199b844fe5501dafaad45d7cb.tar.bz2 dotty-96f754c92713d1a199b844fe5501dafaad45d7cb.zip |
Add constructors phase
Diffstat (limited to 'src/dotty/tools/dotc/transform/Constructors.scala')
-rw-r--r-- | src/dotty/tools/dotc/transform/Constructors.scala | 131 |
1 files changed, 116 insertions, 15 deletions
diff --git a/src/dotty/tools/dotc/transform/Constructors.scala b/src/dotty/tools/dotc/transform/Constructors.scala index 34c90fdc2..d03b90a27 100644 --- a/src/dotty/tools/dotc/transform/Constructors.scala +++ b/src/dotty/tools/dotc/transform/Constructors.scala @@ -1,27 +1,128 @@ -package dotty.tools.dotc.transform +package dotty.tools.dotc +package transform +import core._ import TreeTransforms._ import dotty.tools.dotc.ast.tpd._ import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.StdNames._ +import Phases._ +import ast._ +import Trees._ +import Flags._ +import SymUtils._ +import Symbols._ +import SymDenotations._ +import Types._ +import Decorators._ +import DenotTransformers._ +import ExplicitOuter.outerParamAccessor /** This transform moves initializers from body to constructor. - * Right now it's a dummy. - * Awaiting for real implemetation */ -class Constructors extends MiniPhaseTransform { +class Constructors extends MiniPhaseTransform with SymTransformer { thisTransform => + import tpd._ override def phaseName: String = "constructors" - override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = { - if(tree.symbol.isClassConstructor) { - val claz = tree.symbol.enclosingClass.asClass - val zuper = claz.info.parents.head.typeSymbol - cpy.DefDef(tree)(rhs = { - val parentCall = - Super(This(claz), tpnme.EMPTY, true).select(zuper.primaryConstructor).appliedToNone - if(tree.rhs.isEmpty) parentCall - else Block(List(parentCall), tree.rhs) - }) - } else tree + override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Erasure]) + + override def treeTransformPhase = thisTransform.next + + override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = { + def ownerBecomesConstructor(owner: Symbol): Boolean = + (owner.isLocalDummy || + owner.isTerm && !owner.is(Method) && owner.owner.isClass) && + !owner.enclosingClass.is(Trait) // TODO: Remove qualification once Mixin is operational + if (ownerBecomesConstructor(sym.owner)) + sym.copySymDenotation(owner = sym.owner.enclosingClass.primaryConstructor) + else sym + } + + private def intoConstr(accessors: List[Symbol], params: List[Symbol]) = new TreeMap { + override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match { + case Ident(_) | Select(This(_), _) => + val sym = tree.symbol + if (sym is ParamAccessor) { + val param = sym.subst(accessors, params) + if (param ne sym) ref(param).withPos(tree.pos) + else tree + } + else tree + case Apply(fn, Nil) => + val fn1 = transform(fn) + if ((fn1 ne fn) && + fn1.symbol.is(Param) && + fn1.symbol.owner.isPrimaryConstructor) { + // Two possible cases, which each need their adaptation: + if (fn1.symbol.initial.info.isInstanceOf[ExprType]) + // it's either a call-by-name parameter, which is erased to Function0, + // then we need to insert an apply. + cpy.Apply(tree)(Select(fn1, nme.apply), Nil).ensureConforms(tree.tpe) + else + // or original accessor was an alias accessor, then we need to drop the () + fn1 + } + else cpy.Apply(tree)(fn1, Nil) + case _ => + super.transform(tree) + } + } + + private def splitStats(stats: List[Tree])(implicit ctx: Context): (List[Tree], List[Tree]) = stats match { + case stat :: stats1 => + val (constrStats, clsStats) = splitStats(stats1) + stat match { + case stat @ ValDef(mods, name, tpt, rhs) if !rhs.isEmpty => + val inits = + if (isWildcardArg(rhs)) Nil + else Assign(ref(stat.symbol), rhs).withPos(stat.pos) :: Nil + (inits ::: constrStats, cpy.ValDef(stat)(rhs = EmptyTree) :: clsStats) + case _: DefTree => + (constrStats, stat :: clsStats) + case _ => + (stat :: constrStats, clsStats) + } + case Nil => + (Nil, Nil) + } + + override def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo): Tree = { + val cls = ctx.owner.asClass + if (cls is Trait) tree + else { + val constr @ DefDef(_, nme.CONSTRUCTOR, Nil, vparams :: Nil, _, EmptyTree) = tree.constr + val (superApp @ Apply( + superSel @ Select( + superNew @ New(superType), + nme.CONSTRUCTOR), + superArgs)) :: traitParents = tree.parents + var accessors = cls.paramAccessors.filterNot(_.isSetter) + var vparamsWithOuter = vparams + if (!accessors.hasSameLengthAs(vparams)) { + accessors.reverse match { + case last :: _ if (last.name == nme.OUTER) => + accessors = last :: accessors.init + vparamsWithOuter = ValDef(last.asTerm) :: vparams + case _ => + } + assert(accessors.hasSameLengthAs(vparamsWithOuter), + i"lengths differ for $cls, param accs = $accessors, params = $vparamsWithOuter") + } + val mappedArgs = superArgs.map( + intoConstr(accessors, vparamsWithOuter.map(_.symbol)).transform) + val superCall = + cpy.Apply(superApp)( + cpy.Select(superSel)( + Super(This(cls), tpnme.EMPTY, inConstrCall = true).withPos(superNew.pos), + nme.CONSTRUCTOR), + mappedArgs) + val (constrStats, clsStats) = splitStats(tree.body) + def normalizeOwner(stat: Tree) = { + } + cpy.Template(tree)( + constr = cpy.DefDef(constr)(rhs = Block(superCall :: constrStats, unitLiteral)), + parents = superType :: traitParents, + body = clsStats) + } } }
\ No newline at end of file |