Skip to content

Commit f625d0b

Browse files
committed
Add constructors phase
1 parent 22205cd commit f625d0b

File tree

4 files changed

+125
-20
lines changed

4 files changed

+125
-20
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ class Compiler {
6464
new InterceptedMethods,
6565
new Literalize),
6666
List(new Erasure),
67-
List(new CapturedVars)
67+
List(new CapturedVars),
68+
List(new Constructors)/*,
69+
List(new LambdaLift)*/
6870
)
6971

7072
var runId = 1

src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,11 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
326326
typeDefText(optText(rhs)(" = " ~ _))
327327
}
328328
}
329-
case Template(DefDef(mods, _, tparams, vparamss, _, _), parents, self, stats) =>
329+
case Template(constr @ DefDef(mods, _, tparams, vparamss, _, rhs), parents, self, stats) =>
330330
val tparamsTxt = tparamsText(tparams)
331+
val primaryConstrs = if (rhs.isEmpty) Nil else constr :: Nil
331332
val prefix: Text =
332-
if (vparamss.isEmpty) tparamsTxt
333+
if (vparamss.isEmpty || primaryConstrs.nonEmpty) tparamsTxt
333334
else {
334335
var modsText = modText(mods, "")
335336
if (mods.hasAnnotations && !mods.hasFlags) modsText = modsText ~~ " this"
@@ -340,7 +341,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
340341
val selfName = if (self.name == nme.WILDCARD) "this" else self.name.toString
341342
(selfName ~ optText(self.tpt)(": " ~ _) ~ " =>").close
342343
} provided !self.isEmpty
343-
val bodyText = "{" ~~ selfText ~~ toTextGlobal(stats, "\n") ~ "}"
344+
val bodyText = "{" ~~ selfText ~~ toTextGlobal(primaryConstrs ::: stats, "\n") ~ "}"
344345
prefix ~~ (" extends" provided ownerIsClass) ~~ parentsText ~~ bodyText
345346
case Import(expr, selectors) =>
346347
def selectorText(sel: Tree): Text = sel match {
Lines changed: 116 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,128 @@
1-
package dotty.tools.dotc.transform
1+
package dotty.tools.dotc
2+
package transform
23

4+
import core._
35
import TreeTransforms._
46
import dotty.tools.dotc.ast.tpd._
57
import dotty.tools.dotc.core.Contexts.Context
68
import dotty.tools.dotc.core.StdNames._
9+
import Phases._
10+
import ast._
11+
import Trees._
12+
import Flags._
13+
import SymUtils._
14+
import Symbols._
15+
import SymDenotations._
16+
import Types._
17+
import Decorators._
18+
import DenotTransformers._
19+
import ExplicitOuter.outerParamAccessor
720

821
/** This transform moves initializers from body to constructor.
9-
* Right now it's a dummy.
10-
* Awaiting for real implemetation
1122
*/
12-
class Constructors extends MiniPhaseTransform {
23+
class Constructors extends MiniPhaseTransform with SymTransformer { thisTransform =>
24+
import tpd._
1325

1426
override def phaseName: String = "constructors"
15-
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
16-
if(tree.symbol.isClassConstructor) {
17-
val claz = tree.symbol.enclosingClass.asClass
18-
val zuper = claz.info.parents.head.typeSymbol
19-
cpy.DefDef(tree)(rhs = {
20-
val parentCall =
21-
Super(This(claz), tpnme.EMPTY, true).select(zuper.primaryConstructor).appliedToNone
22-
if(tree.rhs.isEmpty) parentCall
23-
else Block(List(parentCall), tree.rhs)
24-
})
25-
} else tree
27+
override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Erasure])
28+
29+
override def treeTransformPhase = thisTransform.next
30+
31+
override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = {
32+
def ownerBecomesConstructor(owner: Symbol): Boolean =
33+
(owner.isLocalDummy ||
34+
owner.isTerm && !owner.is(Method) && owner.owner.isClass) &&
35+
!owner.enclosingClass.is(Trait) // TODO: Remove qualification once Mixin is operational
36+
if (ownerBecomesConstructor(sym.owner))
37+
sym.copySymDenotation(owner = sym.owner.enclosingClass.primaryConstructor)
38+
else sym
39+
}
40+
41+
private def intoConstr(accessors: List[Symbol], params: List[Symbol]) = new TreeMap {
42+
override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
43+
case Ident(_) | Select(This(_), _) =>
44+
val sym = tree.symbol
45+
if (sym is ParamAccessor) {
46+
val param = sym.subst(accessors, params)
47+
if (param ne sym) ref(param).withPos(tree.pos)
48+
else tree
49+
}
50+
else tree
51+
case Apply(fn, Nil) =>
52+
val fn1 = transform(fn)
53+
if ((fn1 ne fn) &&
54+
fn1.symbol.is(Param) &&
55+
fn1.symbol.owner.isPrimaryConstructor) {
56+
// Two possible cases, which each need their adaptation:
57+
if (fn1.symbol.initial.info.isInstanceOf[ExprType])
58+
// it's either a call-by-name parameter, which is erased to Function0,
59+
// then we need to insert an apply.
60+
cpy.Apply(tree)(Select(fn1, nme.apply), Nil).ensureConforms(tree.tpe)
61+
else
62+
// or original accessor was an alias accessor, then we need to drop the ()
63+
fn1
64+
}
65+
else cpy.Apply(tree)(fn1, Nil)
66+
case _ =>
67+
super.transform(tree)
68+
}
69+
}
70+
71+
private def splitStats(stats: List[Tree])(implicit ctx: Context): (List[Tree], List[Tree]) = stats match {
72+
case stat :: stats1 =>
73+
val (constrStats, clsStats) = splitStats(stats1)
74+
stat match {
75+
case stat @ ValDef(mods, name, tpt, rhs) if !rhs.isEmpty =>
76+
val inits =
77+
if (isWildcardArg(rhs)) Nil
78+
else Assign(ref(stat.symbol), rhs).withPos(stat.pos) :: Nil
79+
(inits ::: constrStats, cpy.ValDef(stat)(rhs = EmptyTree) :: clsStats)
80+
case _: DefTree =>
81+
(constrStats, stat :: clsStats)
82+
case _ =>
83+
(stat :: constrStats, clsStats)
84+
}
85+
case Nil =>
86+
(Nil, Nil)
87+
}
88+
89+
override def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo): Tree = {
90+
val cls = ctx.owner.asClass
91+
if (cls is Trait) tree
92+
else {
93+
val constr @ DefDef(_, nme.CONSTRUCTOR, Nil, vparams :: Nil, _, EmptyTree) = tree.constr
94+
val (superApp @ Apply(
95+
superSel @ Select(
96+
superNew @ New(superType),
97+
nme.CONSTRUCTOR),
98+
superArgs)) :: traitParents = tree.parents
99+
var accessors = cls.paramAccessors.filterNot(_.isSetter)
100+
var vparamsWithOuter = vparams
101+
if (!accessors.hasSameLengthAs(vparams)) {
102+
accessors.reverse match {
103+
case last :: _ if (last.name == nme.OUTER) =>
104+
accessors = last :: accessors.init
105+
vparamsWithOuter = ValDef(last.asTerm) :: vparams
106+
case _ =>
107+
}
108+
assert(accessors.hasSameLengthAs(vparamsWithOuter),
109+
i"lengths differ for $cls, param accs = $accessors, params = $vparamsWithOuter")
110+
}
111+
val mappedArgs = superArgs.map(
112+
intoConstr(accessors, vparamsWithOuter.map(_.symbol)).transform)
113+
val superCall =
114+
cpy.Apply(superApp)(
115+
cpy.Select(superSel)(
116+
Super(This(cls), tpnme.EMPTY, inConstrCall = true).withPos(superNew.pos),
117+
nme.CONSTRUCTOR),
118+
mappedArgs)
119+
val (constrStats, clsStats) = splitStats(tree.body)
120+
def normalizeOwner(stat: Tree) = {
121+
}
122+
cpy.Template(tree)(
123+
constr = cpy.DefDef(constr)(rhs = Block(superCall :: constrStats, unitLiteral)),
124+
parents = superType :: traitParents,
125+
body = clsStats)
126+
}
26127
}
27128
}

test/dotc/tests.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class tests extends CompilerTest {
1313
// "-Yshow-suppressed-errors",
1414
"-pagewidth", "160")
1515

16-
implicit val defaultOptions = noCheckOptions ++ List("-Ycheck:literalize,capturedVars")
16+
implicit val defaultOptions = noCheckOptions ++ List("-Ycheck:literalize,constructors")
1717

1818
val twice = List("#runs", "2", "-YnoDoubleBindings", "-Ystop-before:terminal")
1919
val doErase = List("-Ystop-before:terminal")
@@ -86,6 +86,7 @@ class tests extends CompilerTest {
8686
@Test def nef_t1279a = compileFile(negDir, "t1279a", xerrors = 1)
8787
@Test def neg_t1843 = compileFile(negDir, "t1843", xerrors = 1)
8888
@Test def neg_t1843_variances = compileFile(negDir, "t1843-variances", xerrors = 1)
89+
@Test def neg_t2660_ambi = compileFile(negDir, "t2660", xerrors = 2)
8990
@Test def neg_t2994 = compileFile(negDir, "t2994", xerrors = 2)
9091
@Test def neg_variances = compileFile(negDir, "variances", xerrors = 2)
9192
@Test def neg_badAuxConstr = compileFile(negDir, "badAuxConstr", xerrors = 2)

0 commit comments

Comments
 (0)