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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
package dotty.tools.dotc
package transform
import core._
import Names._
import dotty.tools.dotc.ast.tpd
import dotty.tools.dotc.core.Phases.NeedsCompanions
import dotty.tools.dotc.transform.TreeTransforms._
import ast.Trees._
import Flags._
import Types._
import Constants.Constant
import Contexts.Context
import Symbols._
import SymDenotations._
import Decorators._
import dotty.tools.dotc.core.Annotations.ConcreteAnnotation
import dotty.tools.dotc.core.Denotations.SingleDenotation
import scala.collection.mutable
import DenotTransformers._
import typer.Checking
import Names.Name
import NameOps._
import StdNames._
/** The first tree transform
* - ensures there are companion objects for all classes except module classes
* - eliminates some kinds of trees: Imports, NamedArgs
* - stubs out native methods
*/
class FirstTransform extends MiniPhaseTransform with IdentityDenotTransformer with AnnotationTransformer { thisTransformer =>
import ast.tpd._
override def phaseName = "firstTransform"
private var addCompanionPhases: List[NeedsCompanions] = _
def needsCompanion(cls: ClassSymbol)(implicit ctx: Context) =
addCompanionPhases.exists(_.isCompanionNeeded(cls))
override def prepareForUnit(tree: tpd.Tree)(implicit ctx: Context): TreeTransform = {
addCompanionPhases = ctx.phasePlan.flatMap(_ collect { case p: NeedsCompanions => p })
this
}
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp/*{
tp match {
//create companions for value classes that are not from currently compiled source file
case tp@ClassInfo(_, cls, _, decls, _)
if (ValueClasses.isDerivedValueClass(cls)) &&
!sym.isDefinedInCurrentRun && sym.scalacLinkedClass == NoSymbol =>
val newDecls = decls.cloneScope
val (modul, mcMethod, symMethod) = newCompanion(sym.name.toTermName, sym)
modul.entered
mcMethod.entered
newDecls.enter(symMethod)
tp.derivedClassInfo(decls = newDecls)
case _ => tp
}
}
*/
override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = {
tree match {
case Select(qual, _) if tree.symbol.exists =>
assert(qual.tpe derivesFrom tree.symbol.owner, i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe}")
case _: TypeTree =>
case _: Import | _: NamedArg | _: TypTree =>
assert(false, i"illegal tree: $tree")
case _ =>
}
}
/** Reorder statements so that module classes always come after their companion classes, add missing companion classes */
private def reorderAndComplete(stats: List[Tree])(implicit ctx: Context): List[Tree] = {
val moduleClassDefs, singleClassDefs = mutable.Map[Name, Tree]()
def reorder(stats: List[Tree]): List[Tree] = stats match {
case (stat: TypeDef) :: stats1 if stat.symbol.isClass =>
if (stat.symbol is Flags.Module) {
moduleClassDefs += (stat.name -> stat)
singleClassDefs -= stat.name.stripModuleClassSuffix
val stats1r = reorder(stats1)
if (moduleClassDefs contains stat.name) stat :: stats1r else stats1r
} else {
def stats1r = reorder(stats1)
val normalized = moduleClassDefs remove stat.name.moduleClassName match {
case Some(mcdef) =>
mcdef :: stats1r
case None =>
singleClassDefs += (stat.name -> stat)
stats1r
}
stat :: normalized
}
case stat :: stats1 => stat :: reorder(stats1)
case Nil => Nil
}
def registerCompanion(name: TermName, forClass: Symbol): TermSymbol = {
val (modul, mcCompanion, classCompanion) = newCompanion(name, forClass)
if (ctx.owner.isClass) modul.enteredAfter(thisTransformer)
mcCompanion.enteredAfter(thisTransformer)
classCompanion.enteredAfter(thisTransformer)
modul
}
def addMissingCompanions(stats: List[Tree]): List[Tree] = stats map {
case stat: TypeDef if (singleClassDefs contains stat.name) && needsCompanion(stat.symbol.asClass) =>
val objName = stat.name.toTermName
val nameClash = stats.exists {
case other: MemberDef =>
other.name == objName && other.symbol.info.isParameterless
case _ =>
false
}
val uniqueName = if (nameClash) objName.avoidClashName else objName
Thicket(stat :: ModuleDef(registerCompanion(uniqueName, stat.symbol), Nil).trees)
case stat => stat
}
addMissingCompanions(reorder(stats))
}
private def newCompanion(name: TermName, forClass: Symbol)(implicit ctx: Context) = {
val modul = ctx.newCompleteModuleSymbol(forClass.owner, name, Synthetic, Synthetic,
defn.ObjectType :: Nil, Scopes.newScope, assocFile = forClass.asClass.assocFile)
val mc = modul.moduleClass
val mcComp = ctx.synthesizeCompanionMethod(nme.COMPANION_CLASS_METHOD, forClass, mc)
val classComp = ctx.synthesizeCompanionMethod(nme.COMPANION_MODULE_METHOD, mc, forClass)
(modul, mcComp, classComp)
}
override def transformDefDef(ddef: DefDef)(implicit ctx: Context, info: TransformerInfo) = {
if (ddef.symbol.hasAnnotation(defn.NativeAnnot)) {
ddef.symbol.resetFlag(Deferred)
DefDef(ddef.symbol.asTerm,
_ => ref(defn.Sys_errorR).withPos(ddef.pos)
.appliedTo(Literal(Constant("native method stub"))))
} else ddef
}
override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] =
ast.Trees.flatten(reorderAndComplete(trees)(ctx.withPhase(thisTransformer.next)))
override def transformOther(tree: Tree)(implicit ctx: Context, info: TransformerInfo) = tree match {
case tree: Import => EmptyTree
case tree: NamedArg => transform(tree.arg)
case tree => tree
}
// invariants: all modules have companion objects
// all types are TypeTrees
// all this types are explicit
}
|