@@ -172,7 +172,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
172
172
173
173
/** Add all members to be mixed in into a (non-trait-) class
174
174
* For every mixin trait T that is not also inherited by the superclass:
175
- * - for every abstract accessor in T, add a field and an implementation for that accessor
175
+ * - for every abstract accessor in T, add a field (expanding its name if needed) and an implementation for that accessor
176
176
* - for every super accessor in T, add an implementation of that accessor
177
177
* - for every module in T, add a module
178
178
*
@@ -256,20 +256,27 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
256
256
unit.depends += traitClass
257
257
258
258
for (traitMember <- traitClass.info.decls) {
259
- println(traitMember)
260
- // accessors that need a field (and thus can't ultimately be concrete in a trait)
261
- if (isConcreteAccessor(traitMember)) {
262
- if (! isOverriddenAccessor(traitMember, clazz.info.baseClasses)) {
263
- mixinAccessorSym(traitClass, traitMember)
264
-
265
- // if (traitMember.isLazy) initializer(mixedInAccessor) = traitMember
266
-
267
- // mixin one field only (this method is called for both accessors)
268
- // don't mix in a field at all if it doesn't need storage
269
- if (! (traitMember.isSetter || typeNeedsNoStorage(traitMember.tpe.resultType)))
270
- mixinFieldSym(traitMember)
259
+ // accessors that need an implementation and a field
260
+ val accessor : Boolean = traitMember.isAccessor
261
+ val concrete : Boolean = traitMember hasFlag lateDEFERRED
262
+ val notOverridden : Boolean = ! isOverriddenAccessor(traitMember, clazz.info.baseClasses)
263
+
264
+ println(s " traitMember: $traitMember $accessor/ $concrete/ $notOverridden" )
265
+
266
+ if (accessor) {
267
+ if (concrete) {
268
+ if (notOverridden) {
269
+ mixinAccessorSym(traitClass, traitMember)
270
+
271
+ // if (traitMember.isLazy) initializer(mixedInAccessor) = traitMember
272
+
273
+ // mixin one field only (this method is called for both accessors)
274
+ // don't mix in a field at all if it doesn't need storage
275
+ if (traitMember.isGetter && mustMemoize(traitMember))
276
+ mixinFieldSym(traitMember)
277
+ }
278
+ else devWarning(s " Overridden concrete accessor: ${traitMember.fullLocationString}" )
271
279
}
272
- else devWarning(s " Overridden concrete accessor: ${traitMember.fullLocationString}" )
273
280
} else if (traitMember.isSuperAccessor) {
274
281
val sym = superSym(traitClass, traitMember.alias)
275
282
if (sym ne NoSymbol ) mixinSuperAccessorSym(traitMember, sym)
@@ -297,7 +304,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
297
304
*/
298
305
override def transformInfo (sym : Symbol , tp : Type ): Type = {
299
306
if (sym.isPrivate && sym.owner.isTrait) {
300
- // TODO: why not do this from the start?
307
+ // TODO: why not do this from the start? (maybe because it name-mangles depending on the class??)
301
308
if ((sym hasFlag (ACCESSOR | SUPERACCESSOR ))
302
309
|| sym.isModule // 5
303
310
|| sym.isLocalToThis) // 7 TODO what did `&& sym.getterIn(sym.owner.toInterface) == NoSymbol` do?
@@ -397,14 +404,29 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
397
404
*/
398
405
private def preTransform (tree : Tree ): Tree = {
399
406
val sym = tree.symbol
407
+ val clazz = sym.owner
400
408
tree match {
409
+ // Add super-trait constructor calls `super[mix].$init$()` (in reverse-linearization order) to the body of the ctor
410
+ case DefDef (_,_,_,_,_, Block (_ :: _, _)) if sym.isClassConstructor && sym.isPrimaryConstructor && clazz != ArrayClass =>
411
+ deriveDefDef(tree) { case tree@ Block (stats, expr) =>
412
+ def typedCtorCall (`trait` : Symbol ): Tree =
413
+ typedPos(expr.pos) { Apply (Select (This (clazz), `trait`.primaryConstructor), List ()) }
414
+
415
+ // check `hasExistingSymbol` (via `hasSymbolWhich`) because `supercall` could be a block (named / default args)
416
+ val (preSuper, superCall :: postSuperOrig) = stats span (_ hasSymbolWhich (_ hasFlag PRESUPER ))
417
+ val postSuper = (clazz.mixinClasses map typedCtorCall) reverse_:: : postSuperOrig
418
+ treeCopy.Block (tree, preSuper ::: (superCall :: postSuper), expr)
419
+ }
420
+
401
421
case Template (parents, self, body) if doImplementTraitMembers(currentOwner) =>
402
422
localTyper = erasure.newTyper(rootContext.make(tree, currentOwner))
403
423
exitingMixin(currentOwner.owner.info)// todo: needed?
404
424
405
425
implementTraitMembers(currentOwner, unit)
406
426
407
427
tree
428
+
429
+
408
430
case _ =>
409
431
tree
410
432
}
@@ -873,28 +895,33 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
873
895
else mkCheckedAccessor(clazz, readValue, fieldOffset(getter), getter.pos, getter)
874
896
}
875
897
876
- def setterBody (setter : Symbol ) = {
877
- val getter = setter.getterIn(clazz)
878
-
879
- // A trait with a field of type Unit creates a trait setter (invoked by the
880
- // implementation class constructor), like for any other trait field.
881
- // However, no actual field is created in the class that mixes in the trait.
882
- // Therefore the setter does nothing (except setting the -Xcheckinit flag).
883
-
884
- val setInitFlag =
885
- if (! needsInitFlag(getter)) Nil
886
- else List (mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)))
887
-
888
- val fieldInitializer =
889
- if (isUnitGetter(getter)) Nil
890
- else List (Assign (fieldAccess(setter), Ident (setter.firstParam)))
891
-
892
- (fieldInitializer ::: setInitFlag) match {
893
- case Nil => UNIT
894
- // If there's only one statement, the Block factory does not actually create a Block.
895
- case stats => Block (stats : _* )
898
+ // If this is a setter of a mixed-in field which is overridden by another mixin,
899
+ // the trait setter of the overridden one does not need to do anything - the
900
+ // trait setter of the overriding field will initialize the field.
901
+ def setterBody (setter : Symbol ) =
902
+ if (isOverriddenSetter(setter)) UNIT
903
+ else {
904
+ val getter = setter.getterIn(clazz)
905
+
906
+ // A trait with a field of type Unit creates a trait setter (invoked by the
907
+ // implementation class constructor), like for any other trait field.
908
+ // However, no actual field is created in the class that mixes in the trait.
909
+ // Therefore the setter does nothing (except setting the -Xcheckinit flag).
910
+
911
+ val setInitFlag =
912
+ if (! needsInitFlag(getter)) Nil
913
+ else List (mkSetFlag(clazz, fieldOffset(getter), getter, bitmapKind(getter)))
914
+
915
+ val fieldInitializer =
916
+ if (isUnitGetter(getter)) Nil
917
+ else List (Assign (fieldAccess(setter), Ident (setter.firstParam)))
918
+
919
+ (fieldInitializer ::: setInitFlag) match {
920
+ case Nil => UNIT
921
+ // If there's only one statement, the Block factory does not actually create a Block.
922
+ case stats => Block (stats : _* )
923
+ }
896
924
}
897
- }
898
925
899
926
def isUnitGetter (getter : Symbol ) = getter.tpe.resultType.typeSymbol == UnitClass
900
927
def fieldAccess (accessor : Symbol ) = Select (This (clazz), accessor.accessed)
@@ -929,19 +956,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
929
956
}
930
957
// if class is not a trait add accessor definitions
931
958
else if (! clazz.isTrait) {
932
- if (isConcreteAccessor(sym)) {
933
- // add accessor definitions
934
- addDefDef(sym, {
935
- if (sym.isSetter) {
936
- // If this is a setter of a mixed-in field which is overridden by another mixin,
937
- // the trait setter of the overridden one does not need to do anything - the
938
- // trait setter of the overriding field will initialize the field.
939
- if (isOverriddenSetter(sym)) UNIT
940
- else setterBody(sym)
941
- }
942
- else getterBody(sym)
943
- })
944
- }
959
+ if (sym.isAccessor) addDefDef(sym, if (sym.isSetter) setterBody(sym) else getterBody(sym))
945
960
else if (sym.isModule && ! (sym hasFlag LIFTED | BRIDGE )) {
946
961
// add modules
947
962
val vsym = sym.owner.newModuleVarSymbol(sym)
@@ -964,12 +979,13 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
964
979
// add superaccessors
965
980
addDefDef(sym)
966
981
}
967
- else {
968
- // add forwarders
969
- assert(sym.alias != NoSymbol , sym)
970
- // debuglog("New forwarder: " + sym.defString + " => " + sym.alias.defString)
971
- if (! sym.isMacro) addDefDef(sym, Apply (staticRef(sym.alias), gen.mkAttributedThis(clazz) :: sym.paramss.head.map(Ident )))
972
- }
982
+ // TODO: override methods to encode linearization order
983
+ // else {
984
+ // // add forwarders
985
+ // assert(sym.alias != NoSymbol, sym)
986
+ // // debuglog("New forwarder: " + sym.defString + " => " + sym.alias.defString)
987
+ // if (!sym.isMacro) addDefDef(sym, Apply(staticRef(sym.alias), gen.mkAttributedThis(clazz) :: sym.paramss.head.map(Ident)))
988
+ // }
973
989
}
974
990
}
975
991
stats1 = add(stats1, newDefs.toList)
0 commit comments