@@ -13,6 +13,7 @@ import Decorators._
13
13
import DenotTransformers ._
14
14
import StdNames ._
15
15
import NameKinds ._
16
+ import NameOps ._
16
17
import ast .Trees ._
17
18
import collection .mutable
18
19
@@ -145,32 +146,38 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
145
146
}
146
147
}.asTerm
147
148
149
+ private def wasOneOf (sym : Symbol , flags : FlagSet )(implicit ctx : Context ): Boolean =
150
+ ctx.atPhase(thisPhase) { sym.isOneOf(flags) }
151
+
152
+ private def needsTraitSetter (sym : Symbol )(implicit ctx : Context ): Boolean =
153
+ sym.isGetter && ! wasOneOf(sym, DeferredOrLazy | ParamAccessor ) && ! sym.setter.exists
154
+ && ! sym.info.resultType.isInstanceOf [ConstantType ]
155
+
156
+ private def traitSetter (getter : TermSymbol )(implicit ctx : Context ): Symbol =
157
+ getter.copy(
158
+ name = getter.ensureNotPrivate.name
159
+ .expandedName(getter.owner, TraitSetterName )
160
+ .asTermName.setterName,
161
+ flags = Method | Accessor | Deferred ,
162
+ info = MethodType (getter.info.resultType :: Nil , defn.UnitType ))
163
+
148
164
override def transformTemplate (impl : Template )(implicit ctx : Context ): Template = {
149
165
val cls = impl.symbol.owner.asClass
150
166
val ops = new MixinOps (cls, thisPhase)
151
167
import ops ._
152
168
153
169
def traitDefs (stats : List [Tree ]): List [Tree ] = {
154
- val initBuf = new mutable.ListBuffer [Tree ]
155
- stats.flatMap({
156
- case stat : DefDef if stat.symbol.isGetter && ! stat.rhs.isEmpty && ! stat.symbol.is(Lazy ) =>
157
- // make initializer that has all effects of previous getter,
158
- // replace getter rhs with empty tree.
159
- val vsym = stat.symbol
160
- val isym = initializer(vsym)
161
- val rhs = Block (
162
- initBuf.toList.map(_.changeOwnerAfter(impl.symbol, isym, thisPhase)),
163
- stat.rhs.changeOwnerAfter(vsym, isym, thisPhase).wildcardToDefault)
164
- initBuf.clear()
165
- cpy.DefDef (stat)(rhs = EmptyTree ) :: DefDef (isym, rhs) :: Nil
170
+ stats.flatMap {
171
+ case stat : DefDef if needsTraitSetter(stat.symbol) =>
172
+ // add a trait setter for this getter
173
+ val vsym = stat.symbol.asTerm
174
+ val ssym = traitSetter(vsym).asTerm.enteredAfter(thisPhase)
175
+ stat :: DefDef (ssym, EmptyTree ) :: Nil
166
176
case stat : DefDef if stat.symbol.isSetter =>
167
177
cpy.DefDef (stat)(rhs = EmptyTree ) :: Nil
168
- case stat : DefTree =>
169
- stat :: Nil
170
178
case stat =>
171
- initBuf += stat
172
- Nil
173
- }) ++ initBuf
179
+ stat :: Nil
180
+ }
174
181
}
175
182
176
183
/** Map constructor call to a pair of a supercall and a list of arguments
@@ -205,9 +212,6 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
205
212
transformFollowingDeep(superRef(baseCls.primaryConstructor).appliedToNone) :: Nil
206
213
}
207
214
208
- def wasOneOf (sym : Symbol , flags : FlagSet ) =
209
- ctx.atPhase(thisPhase) { sym.isOneOf(flags) }
210
-
211
215
def traitInits (mixin : ClassSymbol ): List [Tree ] = {
212
216
var argNum = 0
213
217
def nextArgument () = initArgs.get(mixin) match {
@@ -227,33 +231,28 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
227
231
}
228
232
229
233
for (getter <- mixin.info.decls.toList if getter.isGetter && ! wasOneOf(getter, Deferred )) yield {
230
- val isScala2x = mixin.is(Scala2x )
231
- def default = Underscore (getter.info.resultType)
232
- def initial = transformFollowing(superRef(initializer(getter)).appliedToNone)
233
-
234
234
if (isCurrent(getter) || getter.name.is(ExpandedName )) {
235
235
val rhs =
236
236
if (wasOneOf(getter, ParamAccessor ))
237
237
nextArgument()
238
- else if (isScala2x)
239
- if (getter.is(Lazy , butNot = Module ))
240
- initial
241
- else if (getter.is(Module ))
242
- New (getter.info.resultType, List (This (cls)))
243
- else
244
- Underscore (getter.info.resultType)
238
+ else if (getter.is(Lazy , butNot = Module ))
239
+ transformFollowing(superRef(getter).appliedToNone)
240
+ else if (getter.is(Module ))
241
+ New (getter.info.resultType, List (This (cls)))
245
242
else
246
- initial
243
+ Underscore (getter.info.resultType)
247
244
// transformFollowing call is needed to make memoize & lazy vals run
248
245
transformFollowing(DefDef (mkForwarderSym(getter.asTerm), rhs))
249
246
}
250
- else if (isScala2x || wasOneOf(getter, ParamAccessor | Lazy )) EmptyTree
251
- else initial
247
+ else EmptyTree
252
248
}
253
249
}
254
250
255
251
def setters (mixin : ClassSymbol ): List [Tree ] =
256
- for (setter <- mixin.info.decls.filter(setr => setr.isSetter && ! wasOneOf(setr, Deferred )))
252
+ val mixinSetters = mixin.info.decls.filter { sym =>
253
+ sym.isSetter && (! wasOneOf(sym, Deferred ) || sym.name.is(TraitSetterName ))
254
+ }
255
+ for (setter <- mixinSetters)
257
256
yield transformFollowing(DefDef (mkForwarderSym(setter.asTerm), unitLiteral.withSpan(cls.span)))
258
257
259
258
def mixinForwarders (mixin : ClassSymbol ): List [Tree ] =
0 commit comments