1
- package dotty .tools .dotc .transform
1
+ package dotty .tools .dotc
2
+ package transform
2
3
4
+ import core ._
3
5
import TreeTransforms ._
4
6
import dotty .tools .dotc .ast .tpd ._
5
7
import dotty .tools .dotc .core .Contexts .Context
6
8
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
7
20
8
21
/** This transform moves initializers from body to constructor.
9
- * Right now it's a dummy.
10
- * Awaiting for real implemetation
11
22
*/
12
- class Constructors extends MiniPhaseTransform {
23
+ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransform =>
24
+ import tpd ._
13
25
14
26
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
+ }
26
127
}
27
128
}
0 commit comments