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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
|
/* NSC -- new scala compiler
* Copyright 2005-2011 LAMP/EPFL
* @author Martin Odersky
*/
package scala.reflect
package internal
import scala.collection.{ mutable, immutable }
import util._
import scala.tools.nsc.util.WeakHashSet
abstract class SymbolTable extends api.Universe
with Collections
with Names
with SymbolCreations
with Symbols
with SymbolFlags
with Types
with Kinds
with ExistentialsAndSkolems
with Scopes
with Definitions
with Constants
with BaseTypeSeqs
with InfoTransformers
with transform.Transforms
with StdNames
with AnnotationInfos
with AnnotationCheckers
with Trees
with TreePrinters
with Positions
with TypeDebugging
with Importers
with Required
{
def rootLoader: LazyType
def log(msg: => AnyRef): Unit
def abort(msg: String): Nothing = throw new FatalError(supplementErrorMessage(msg))
@deprecated("Give us a reason", "2.10.0")
def abort(): Nothing = abort("unknown error")
/** Override with final implementation for inlining. */
def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg)
def debugwarn(msg: => String): Unit = if (settings.debug.value) Console.err.println(msg)
/** Overridden when we know more about what was happening during a failure. */
def supplementErrorMessage(msg: String): String = msg
private[scala] def printResult[T](msg: String)(result: T) = {
Console.err.println(msg + ": " + result)
result
}
private[scala] def logResult[T](msg: String)(result: T): T = {
log(msg + ": " + result)
result
}
private[scala] def logResultIf[T](msg: String, cond: T => Boolean)(result: T): T = {
if (cond(result))
log(msg + ": " + result)
result
}
/** Dump each symbol to stdout after shutdown.
*/
final val traceSymbolActivity = sys.props contains "scalac.debug.syms"
object traceSymbols extends {
val global: SymbolTable.this.type = SymbolTable.this
} with util.TraceSymbolActivity
/** Are we compiling for Java SE? */
// def forJVM: Boolean
/** Are we compiling for .NET? */
def forMSIL: Boolean = false
/** A last effort if symbol in a select <owner>.<name> is not found.
* This is overridden by the reflection compiler to make up a package
* when it makes sense (i.e. <owner> is a package and <name> is a term name).
*/
def missingHook(owner: Symbol, name: Name): Symbol = NoSymbol
/** A period is an ordinal number for a phase in a run.
* Phases in later runs have higher periods than phases in earlier runs.
* Later phases have higher periods than earlier phases in the same run.
*/
type Period = Int
final val NoPeriod = 0
/** An ordinal number for compiler runs. First run has number 1. */
type RunId = Int
final val NoRunId = 0
// sigh, this has to be public or atPhase doesn't inline.
var phStack: List[Phase] = Nil
private var ph: Phase = NoPhase
private var per = NoPeriod
final def atPhaseStack: List[Phase] = phStack
final def phase: Phase = ph
def atPhaseStackMessage = atPhaseStack match {
case Nil => ""
case ps => ps.reverseMap("->" + _).mkString("(", " ", ")")
}
final def phase_=(p: Phase) {
//System.out.println("setting phase to " + p)
assert((p ne null) && p != NoPhase, p)
ph = p
per = period(currentRunId, p.id)
}
final def pushPhase(ph: Phase): Phase = {
val current = phase
phase = ph
phStack ::= ph
current
}
final def popPhase(ph: Phase) {
phStack = phStack.tail
phase = ph
}
/** The current compiler run identifier. */
def currentRunId: RunId
/** The run identifier of the given period. */
final def runId(period: Period): RunId = period >> 8
/** The phase identifier of the given period. */
final def phaseId(period: Period): Phase#Id = period & 0xFF
/** The period at the start of run that includes `period`. */
final def startRun(period: Period): Period = period & 0xFFFFFF00
/** The current period. */
final def currentPeriod: Period = {
//assert(per == (currentRunId << 8) + phase.id)
per
}
/** The phase associated with given period. */
final def phaseOf(period: Period): Phase = phaseWithId(phaseId(period))
final def period(rid: RunId, pid: Phase#Id): Period =
(rid << 8) + pid
/** Are we later than given phase in compilation? */
final def isAtPhaseAfter(p: Phase) =
p != NoPhase && phase.id > p.id
/** Perform given operation at given phase. */
@inline final def atPhase[T](ph: Phase)(op: => T): T = {
val saved = pushPhase(ph)
try op
finally popPhase(saved)
}
/** Since when it is to be "at" a phase is inherently ambiguous,
* a couple unambiguously named methods.
*/
@inline final def beforePhase[T](ph: Phase)(op: => T): T = atPhase(ph)(op)
@inline final def afterPhase[T](ph: Phase)(op: => T): T = atPhase(ph.next)(op)
@inline final def afterCurrentPhase[T](op: => T): T = atPhase(phase.next)(op)
@inline final def beforePrevPhase[T](op: => T): T = atPhase(phase.prev)(op)
@inline final def atPhaseNotLaterThan[T](target: Phase)(op: => T): T =
if (isAtPhaseAfter(target)) atPhase(target)(op) else op
final def isValid(period: Period): Boolean =
period != 0 && runId(period) == currentRunId && {
val pid = phaseId(period)
if (phase.id > pid) infoTransformers.nextFrom(pid).pid >= phase.id
else infoTransformers.nextFrom(phase.id).pid >= pid
}
final def isValidForBaseClasses(period: Period): Boolean = {
def noChangeInBaseClasses(it: InfoTransformer, limit: Phase#Id): Boolean = (
it.pid >= limit ||
!it.changesBaseClasses && noChangeInBaseClasses(it.next, limit)
);
period != 0 && runId(period) == currentRunId && {
val pid = phaseId(period)
if (phase.id > pid) noChangeInBaseClasses(infoTransformers.nextFrom(pid), phase.id)
else noChangeInBaseClasses(infoTransformers.nextFrom(phase.id), pid)
}
}
def openPackageModule(container: Symbol, dest: Symbol) {
// unlink existing symbols in the package
for (member <- container.info.decls.iterator) {
if (!member.isPrivate && !member.isConstructor) {
// todo: handle overlapping definitions in some way: mark as errors
// or treat as abstractions. For now the symbol in the package module takes precedence.
for (existing <- dest.info.decl(member.name).alternatives)
dest.info.decls.unlink(existing)
}
}
// enter non-private decls the class
for (member <- container.info.decls.iterator) {
if (!member.isPrivate && !member.isConstructor) {
dest.info.decls.enter(member)
}
}
// enter decls of parent classes
for (p <- container.parentSymbols) {
if (p != definitions.ObjectClass) {
openPackageModule(p, dest)
}
}
}
/** Convert array parameters denoting a repeated parameter of a Java method
* to `JavaRepeatedParamClass` types.
*/
def arrayToRepeated(tp: Type): Type = tp match {
case MethodType(params, rtpe) =>
val formals = tp.paramTypes
assert(formals.last.typeSymbol == definitions.ArrayClass)
val method = params.last.owner
val elemtp = formals.last.typeArgs.head match {
case RefinedType(List(t1, t2), _) if (t1.typeSymbol.isAbstractType && t2.typeSymbol == definitions.ObjectClass) =>
t1 // drop intersection with Object for abstract types in varargs. UnCurry can handle them.
case t =>
t
}
val newParams = method.newSyntheticValueParams(
formals.init :+ appliedType(definitions.JavaRepeatedParamClass.typeConstructor, List(elemtp)))
MethodType(newParams, rtpe)
case PolyType(tparams, rtpe) =>
PolyType(tparams, arrayToRepeated(rtpe))
}
abstract class SymLoader extends LazyType {
def fromSource = false
}
/** if there's a `package` member object in `pkgClass`, enter its members into it. */
def openPackageModule(pkgClass: Symbol) {
val pkgModule = pkgClass.info.decl(nme.PACKAGEkw)
def fromSource = pkgModule.rawInfo match {
case ltp: SymLoader => ltp.fromSource
case _ => false
}
if (pkgModule.isModule && !fromSource) {
// println("open "+pkgModule)//DEBUG
openPackageModule(pkgModule, pkgClass)
}
}
object perRunCaches {
import java.lang.ref.WeakReference
import scala.runtime.ScalaRunTime.stringOf
// We can allow ourselves a structural type, these methods
// amount to a few calls per run at most. This does suggest
// a "Clearable" trait may be useful.
private type Clearable = {
def size: Int
def clear(): Unit
}
// Weak references so the garbage collector will take care of
// letting us know when a cache is really out of commission.
private val caches = mutable.HashSet[WeakReference[Clearable]]()
private def dumpCaches() {
println(caches.size + " structures are in perRunCaches.")
caches.zipWithIndex foreach { case (ref, index) =>
val cache = ref.get()
println("(" + index + ")" + (
if (cache == null) " has been collected."
else " has " + cache.size + " entries:\n" + stringOf(cache)
))
}
}
// if (settings.debug.value) {
// println(Signallable("dump compiler caches")(dumpCaches()))
// }
def recordCache[T <: Clearable](cache: T): T = {
caches += new WeakReference(cache)
cache
}
def clearAll() = {
if (settings.debug.value) {
val size = caches flatMap (ref => Option(ref.get)) map (_.size) sum;
log("Clearing " + caches.size + " caches totalling " + size + " entries.")
}
caches foreach { ref =>
val cache = ref.get()
if (cache == null)
caches -= ref
else
cache.clear()
}
}
def newWeakMap[K, V]() = recordCache(mutable.WeakHashMap[K, V]())
def newMap[K, V]() = recordCache(mutable.HashMap[K, V]())
def newSet[K]() = recordCache(mutable.HashSet[K]())
def newWeakSet[K <: AnyRef]() = recordCache(new WeakHashSet[K]())
}
/** Break into repl debugger if assertion is true. */
// def breakIf(assertion: => Boolean, args: Any*): Unit =
// if (assertion)
// ILoop.break(args.toList)
/** The set of all installed infotransformers. */
var infoTransformers = new InfoTransformer {
val pid = NoPhase.id
val changesBaseClasses = true
def transform(sym: Symbol, tpe: Type): Type = tpe
}
/** The phase which has given index as identifier. */
val phaseWithId: Array[Phase]
/** Is this symbol table part of reflexive mirror? In this case
* operations need to be made thread safe.
*/
def inReflexiveMirror = false
}
|