Skip to content

Commit 3e0b574

Browse files
committed
wip:new mixin: fields
1 parent 9cf5384 commit 3e0b574

File tree

3 files changed

+132
-98
lines changed

3 files changed

+132
-98
lines changed

src/compiler/scala/tools/nsc/transform/Mixin.scala

Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
172172

173173
/** Add all members to be mixed in into a (non-trait-) class
174174
* 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
176176
* - for every super accessor in T, add an implementation of that accessor
177177
* - for every module in T, add a module
178178
*
@@ -256,20 +256,27 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
256256
unit.depends += traitClass
257257

258258
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}")
271279
}
272-
else devWarning(s"Overridden concrete accessor: ${traitMember.fullLocationString}")
273280
} else if (traitMember.isSuperAccessor) {
274281
val sym = superSym(traitClass, traitMember.alias)
275282
if (sym ne NoSymbol) mixinSuperAccessorSym(traitMember, sym)
@@ -297,7 +304,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
297304
*/
298305
override def transformInfo(sym: Symbol, tp: Type): Type = {
299306
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??)
301308
if ((sym hasFlag (ACCESSOR | SUPERACCESSOR))
302309
|| sym.isModule // 5
303310
|| 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 {
397404
*/
398405
private def preTransform(tree: Tree): Tree = {
399406
val sym = tree.symbol
407+
val clazz = sym.owner
400408
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+
401421
case Template(parents, self, body) if doImplementTraitMembers(currentOwner) =>
402422
localTyper = erasure.newTyper(rootContext.make(tree, currentOwner))
403423
exitingMixin(currentOwner.owner.info)//todo: needed?
404424

405425
implementTraitMembers(currentOwner, unit)
406426

407427
tree
428+
429+
408430
case _ =>
409431
tree
410432
}
@@ -873,28 +895,33 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
873895
else mkCheckedAccessor(clazz, readValue, fieldOffset(getter), getter.pos, getter)
874896
}
875897

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+
}
896924
}
897-
}
898925

899926
def isUnitGetter(getter: Symbol) = getter.tpe.resultType.typeSymbol == UnitClass
900927
def fieldAccess(accessor: Symbol) = Select(This(clazz), accessor.accessed)
@@ -929,19 +956,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
929956
}
930957
// if class is not a trait add accessor definitions
931958
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))
945960
else if (sym.isModule && !(sym hasFlag LIFTED | BRIDGE)) {
946961
// add modules
947962
val vsym = sym.owner.newModuleVarSymbol(sym)
@@ -964,12 +979,13 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
964979
// add superaccessors
965980
addDefDef(sym)
966981
}
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+
// }
973989
}
974990
}
975991
stats1 = add(stats1, newDefs.toList)

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3265,7 +3265,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
32653265

32663266
override def existentialBound = GenPolyType(this.typeParams, TypeBounds.upper(this.classBound))
32673267

3268-
def primaryConstructorName = if (this hasFlag TRAIT | IMPLCLASS) nme.MIXIN_CONSTRUCTOR else nme.CONSTRUCTOR
3268+
def primaryConstructorName = if (this hasFlag TRAIT) nme.MIXIN_CONSTRUCTOR else nme.CONSTRUCTOR
32693269

32703270
override def primaryConstructor = {
32713271
val c = info decl primaryConstructorName
Lines changed: 60 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,62 @@
1-
trait T {
2-
val abs: String
3-
protected val protabs: String
4-
val pub = "public"
5-
protected val prot = "protected"
6-
private val privvy = "private"
7-
private[this] val privateThis = "private[this]"
8-
9-
trait Nested { println(abs + privateThis) }
10-
11-
object NO {
12-
println(abs)
13-
println(pub)
14-
println(prot)
15-
println(protabs)
16-
println(privvy)
17-
println(privateThis)
18-
}
19-
20-
trait NT {
21-
println(abs)
22-
println(pub)
23-
println(prot)
24-
println(protabs)
25-
println(privvy)
26-
println(privateThis)
27-
}
28-
29-
class NC {
30-
println(abs)
31-
println(pub)
32-
println(prot)
33-
println(protabs)
34-
println(privvy)
35-
println(privateThis)
36-
}
37-
}
38-
39-
class C extends T {
40-
val abs = "abstract"
41-
val protabs = "abstract protected"
1+
class Meh {
2+
final val x = 1
3+
def foo = x
424
}
435

44-
object Test extends C with App
6+
// class CE extends Empty
7+
//
8+
// trait T {
9+
// val abs: String
10+
// protected val protabs: String
11+
// val pub = "public"
12+
// protected val prot = "protected"
13+
// private val privvy = "private"
14+
// private[this] val privateThis = "private[this]"
15+
// // TODO:
16+
// // final val const = "const"
17+
//
18+
// trait Nested { println(abs + privateThis) }
19+
//
20+
// object NO {
21+
// println(abs)
22+
// println(pub)
23+
// println(prot)
24+
// println(protabs)
25+
// println(privvy)
26+
// println(privateThis)
27+
// }
28+
//
29+
// trait NT {
30+
// println(abs)
31+
// println(pub)
32+
// println(prot)
33+
// println(protabs)
34+
// println(privvy)
35+
// println(privateThis)
36+
// }
37+
//
38+
// class NC {
39+
// println(abs)
40+
// println(pub)
41+
// println(prot)
42+
// println(protabs)
43+
// println(privvy)
44+
// println(privateThis)
45+
// }
46+
// }
47+
//
48+
// class C extends AnyRef with T {
49+
// println("x")
50+
// val abs = "abstract"
51+
// println("y")
52+
// val protabs = "abstract protected"
53+
// final val const = "const"
54+
// println("z")
55+
// }
56+
//
57+
// object Test extends C {
58+
// def main(args: Array[String]): Unit = {
59+
// NO
60+
// new NT{}
61+
// new NC
62+
// }}

0 commit comments

Comments
 (0)