1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/* NSC -- new Scala compiler
* Copyright 2005-2013 LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc
package transform
import symtab._
import Flags._
abstract class AddInterfaces extends InfoTransform { self: Erasure =>
import global._ // the global environment
import definitions._ // standard classes and methods
/** lateDEFERRED for formerly concrete methods in such traits.
*/
override def phaseNewFlags: Long = lateDEFERRED
def transformMixinInfo(tp: Type): Type = tp match {
case ClassInfoType(parents, decls, clazz) if clazz.isPackageClass || !clazz.isJavaDefined =>
val parents1 = parents match {
case Nil => Nil
case hd :: tl =>
assert(!hd.typeSymbol.isTrait, clazz)
if (clazz.isTrait) ObjectTpe :: tl
else parents
}
if (clazz.isTrait) {
decls foreach { sym =>
if (!sym.isType) sym.info // initialize to set lateMETHOD flag if necessary
}
}
if (parents1 eq parents) tp
else ClassInfoType(parents1, decls, clazz)
case _ =>
tp
}
// Tree transformation --------------------------------------------------------------
private class ChangeOwnerAndReturnTraverser(oldowner: Symbol, newowner: Symbol)
extends ChangeOwnerTraverser(oldowner, newowner) {
override def traverse(tree: Tree) {
tree match {
case _: Return => change(tree.symbol)
case _ =>
}
super.traverse(tree)
}
}
private def mkAssign(clazz: Symbol, assignSym: Symbol, rhs: Tree): Tree = {
val qual = Select(This(clazz), assignSym)
if (assignSym.isSetter) Apply(qual, List(rhs))
else Assign(qual, rhs)
}
/** Add calls to supermixin constructors
* `super[mix].$init$()`
* to tree, which is assumed to be the body of a constructor of class clazz.
*/
private def addMixinConstructorCalls(tree: Tree, clazz: Symbol): Tree = {
def mixinConstructorCall(mc: Symbol): Tree = atPos(tree.pos) {
Apply(SuperSelect(clazz, mc.primaryConstructor), Nil)
}
val mixinConstructorCalls: List[Tree] = {
for (mc <- clazz.mixinClasses.reverse
if mc.isTrait && mc.primaryConstructor != NoSymbol)
yield mixinConstructorCall(mc)
}
tree match {
case Block(Nil, expr) =>
// AnyVal constructor - have to provide a real body so the
// jvm doesn't throw a VerifyError. But we can't add the
// body until now, because the typer knows that Any has no
// constructor and won't accept a call to super.init.
assert((clazz isSubClass AnyValClass) || clazz.info.parents.isEmpty, clazz)
Block(List(Apply(gen.mkSuperInitCall, Nil)), expr)
case Block(stats, expr) =>
// needs `hasSymbolField` check because `supercall` could be a block (named / default args)
val (presuper, supercall :: rest) = stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER))
treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr)
}
}
protected val mixinTransformer = new Transformer {
override def transform(tree: Tree): Tree = {
val sym = tree.symbol
val tree1 = tree match {
case DefDef(_,_,_,_,_,_) if sym.isClassConstructor && sym.isPrimaryConstructor && sym.owner != ArrayClass =>
deriveDefDef(tree)(addMixinConstructorCalls(_, sym.owner)) // (3)
case Template(parents, self, body) =>
val parents1 = sym.owner.info.parents map (t => TypeTree(t) setPos tree.pos)
treeCopy.Template(tree, parents1, noSelfType, body)
case _ =>
tree
}
super.transform(tree1)
}
}
}
|