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
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
|
package dotty.tools.dotc
package core
import Denotations.Denotation
import Contexts.Context
import Names.Name
import Names.TypeName
import Symbols.NoSymbol
import Symbols.Symbol
import Types._, Periods._, Flags._, Transformers._
/** Classes that implement referenced items and sets of them
*/
object Referenceds {
/** The signature of a referenced.
* Overloaded referenceds with the same name are distinguished by
* their signatures. A signature is a list of the fully qualified names
* of the type symbols of the erasure of the parameters of the
* referenced. For instance a referenced definition
*
* def f(x: Int)(y: List[String]): String
*
* would have signature
*
* List("scala.Int".toTypeName, "scala.collection.immutable.List".toTypeName)
*/
type Signature = List[TypeName]
/** The signature of a val or parameterless def, as opposed
* to List(), which is the signature of a zero-parameter def.
*/
val NullSignature = List(Names.EmptyTypeName)
/** A referenced is the result of resolving
* a name (either simple identifier or select) during a given period.
*
* Referenced has two subclasses: OverloadedRefd and SymRefd.
*
* A SymRefd refers to a `symbol` and a type (`info`) that the symbol has
* when seen from the reference.
*
* Referenceds can be combined with `&` and `|`.
* & is conjunction, | is disjunction.
*
* `&` will create an overloaded reference from two
* non-overloaded references if their signatures differ.
* Analogously `|` of two references with different signatures will give
* an empty reference `NoRefd`.
*
* A referenced might refer to `NoSymbol`. This is the case if the referenced
* was produced from a disjunction of two referenceds with different symbols
* and there was no common symbol in a superclass that could substitute for
* both symbols. Here is an example:
*
* Say, we have:
*
* class A { def f: A }
* class B { def f: B }
* val x: A | B = if (???) new A else new B
* val y = x.f
*
* Then the referenced of `y` is `SymRefd(NoSymbol, A | B)`.
*/
abstract class Referenced extends DotClass {
/** The referenced symbol, exists only for non-overloaded references */
def symbol: Symbol
/** The type info of the reference, exists only for non-overloaded references */
def info: Type
/** The period during which this reference is valid. */
def validFor: Period
/** Is this a reference to a type symbol? */
def isType: Boolean = false
/** The signature of the reference */
def signature: Signature
/** Resolve overloaded reference to pick the one with the given signature */
def atSignature(sig: Signature): Referenced
/** The variant of this reference that's current in the given context. */
def current(implicit ctx: Context): Referenced
def exists: Boolean = true
def orElse(that: => Referenced) = if (this.exists) this else that
/** Form a reference by conjoining with reference `that` */
def & (that: Referenced)(implicit ctx: Context): Referenced =
if (this eq that) this
else if (!this.exists) that
else if (!that.exists) this
else that match {
case that: SymRefd =>
val r = mergeRef(this, that)
if (r ne NoRefd) r else OverloadedRef(this, that)
case that @ OverloadedRef(ref1, ref2) =>
this & ref1 & ref2
}
/** Try to merge ref1 and ref2 without adding a new signature.
* If unsuccessful, return NoRefd.
*/
private def mergeRef(ref1: Referenced, ref2: SymRefd)(implicit ctx: Context): Referenced = ref1 match {
case ref1 @ OverloadedRef(ref11, ref12) =>
val r1 = mergeRef(ref11, ref2)
if (r1 ne NoRefd) r1 else mergeRef(ref12, ref2)
case ref1: SymRefd =>
if (ref1 eq ref2) ref1
else if (ref1.signature == ref2.signature) {
def isEligible(sym1: Symbol, sym2: Symbol) =
if (sym1.isType) !sym1.isClass
else sym1.isConcrete || sym2.isDeferred || !sym2.exists
def normalize(info: Type) =
if (isType) info.bounds else info
val sym1 = ref1.symbol
val info1 = ref1.info
val sym2 = ref2.symbol
val info2 = ref2.info
val sym1Eligible = isEligible(sym1, sym2)
val sym2Eligible = isEligible(sym2, sym1)
val bounds1 = normalize(info1)
val bounds2 = normalize(info2)
if (sym2Eligible && bounds2 <:< bounds1) ref2
else if (sym1Eligible && bounds1 <:< bounds2) ref1
else new JointSymRefd(
if (sym2Eligible) sym2 else sym1,
bounds1 & bounds2,
ref1.validFor & ref2.validFor)
} else NoRefd
}
def | (that: Referenced)(pre: Type)(implicit ctx: Context): Referenced = {
def lubSym(sym1: Symbol, sym2: Symbol): Symbol = {
def qualifies(sym: Symbol) =
(sym isAccessibleFrom pre) && (sym2.owner isSubClass sym.owner)
sym1.allOverriddenSymbols find qualifies getOrElse NoSymbol
}
def throwError = throw new MatchError(s"orRef($this, $that)")
if (this eq that) this
else if (!this.exists) this
else if (!that.exists) that
else this match {
case ref1 @ OverloadedRef(ref11, ref12) =>
ref1.derivedOverloadedRef((ref11 | that)(pre), (ref12 | that)(pre))
case _ =>
that match {
case ref2 @ OverloadedRef(ref21, ref22) =>
ref2.derivedOverloadedRef((this | ref21)(pre), (this | ref22)(pre))
case ref2: SymRefd =>
this match {
case ref1: SymRefd =>
if (ref1.signature != ref2.signature) NoRefd
else new JointSymRefd(
lubSym(ref1.symbol, ref2.symbol),
ref1.info | ref2.info,
ref1.validFor & ref2.validFor)
case _ =>
throwError
}
case _ =>
throwError
}
}
}
}
/** The class of overloaded references
* @param variants The overloaded variants indexed by thheir signatures.
*/
case class OverloadedRef(ref1: Referenced, ref2: Referenced) extends Referenced {
def derivedOverloadedRef(r1: Referenced, r2: Referenced) =
if ((r1 eq ref1) && (r2 eq ref2)) this else OverloadedRef(r1, r2)
def symbol = unsupported("symbol")
def info = unsupported("info")
def signature = unsupported("signature")
def atSignature(sig: Signature): Referenced =
ref1.atSignature(sig) orElse ref2.atSignature(sig)
def validFor = ref1.validFor & ref2.validFor
def current(implicit ctx: Context): Referenced =
derivedOverloadedRef(ref1.current, ref2.current)
}
abstract class SymRefd extends Referenced with ReferencedSet {
override def isType = symbol.isType
override def signature: Signature = {
def sig(tp: Type): Signature = tp match {
case tp: PolyType =>
tp.resultType match {
case mt: MethodType => mt.signature
case _ => List()
}
case mt: MethodType => mt.signature
case _ => NullSignature
}
if (isType) NullSignature else sig(info)
}
def derivedSymRefd(s: Symbol, i: Type): SymRefd =
if ((s eq symbol) && (i eq info)) this else copy(s, i)
protected def copy(s: Symbol, i: Type): SymRefd = this
def atSignature(sig: Signature): Referenced =
if (sig == signature) this else NoRefd
// ------ Transformations -----------------------------------------
private[this] var _validFor: Period = Nowhere
def validFor = _validFor
def validFor_=(p: Period) =
_validFor = p
/** The next SymRefd in this run, with wrap-around from last to first.
*
* There may be several `SymRefd`s with different validity
* representing the same underlying definition at different phases.
* These are called a "flock". Flock members are generated by
* @see SymRef.current. Flock members are connected in a ring
* with their `nextInRun` fields.
*
* There are the following invariants converning flock members
*
* 1) validity periods must be non-overlapping
* 2) the union of all validity periods must be a contiguous
* interval starting in FirstPhaseId.
*/
var nextInRun: SymRefd = this
/** The version of this SymRefd that was valid in the first phase
* of this run.
*/
def initial: SymRefd = {
var current = nextInRun
while (current.validFor.code > this._validFor.code) current = current.nextInRun
current
}
def current(implicit ctx: Context): SymRefd = {
val currentPeriod = ctx.period
val valid = _validFor
var current = this
if (currentPeriod.code > valid.code) {
// search for containing period as long as nextInRun increases.
var next = nextInRun
while (next.validFor.code > valid.code &&
!(next.validFor contains currentPeriod)) {
current = next
next = next.nextInRun
}
if (next.validFor.code > valid.code) {
// in this case, containsPeriod(next._validFor, currentPeriod)
current = next
} else {
// not found, current points to highest existing variant
var startPid = current.validFor.lastPhaseId + 1
val trans = ctx.root.transformersFor(current)
val endPid = trans.nextTransformer(startPid + 1).phaseId - 1
next = trans.nextTransformer(startPid) transform current
if (next eq current)
startPid = current.validFor.firstPhaseId
else {
current.nextInRun = next
current = next
}
current.validFor = Period(currentPeriod.runId, startPid, endPid)
}
} else {
// currentPeriod < valid; in this case a version must exist
do {
current = current.nextInRun
} while (!(current.validFor contains currentPeriod))
}
current
}
def asDenotation = asInstanceOf[Denotation]
// ------ ReferencedSet ops ----------------------------------------------
def toRef(implicit ctx: Context) = this
def containsSig(sig: Signature)(implicit ctx: Context) =
signature == sig
def filter(p: Symbol => Boolean)(implicit ctx: Context): ReferencedSet =
if (p(symbol)) this else NoRefd
def filterDisjoint(refs: ReferencedSet)(implicit ctx: Context): ReferencedSet =
if (refs.containsSig(signature)) NoRefd else this
def filterExcluded(flags: FlagSet)(implicit ctx: Context): ReferencedSet =
if (symbol.hasFlag(flags)) NoRefd else this
def filterAccessibleFrom(pre: Type)(implicit ctx: Context): ReferencedSet =
if (symbol.isAccessibleFrom(pre)) this else NoRefd
def asSeenFrom(pre: Type, owner: Symbol)(implicit ctx: Context): ReferencedSet =
derivedSymRefd(symbol, info.asSeenFrom(pre, owner))
}
class UniqueSymRefd(val symbol: Symbol,
val info: Type,
initValidFor: Period) extends SymRefd {
validFor = initValidFor
override protected def copy(s: Symbol, i: Type): SymRefd = new UniqueSymRefd(s, i, validFor)
}
class JointSymRefd(val symbol: Symbol,
val info: Type,
initValidFor: Period) extends SymRefd {
validFor = initValidFor
override protected def copy(s: Symbol, i: Type): SymRefd = new JointSymRefd(s, i, validFor)
}
class ErrorRefd(implicit ctx: Context) extends SymRefd {
val symbol = NoSymbol
val info = NoType
validFor = Period.allInRun(ctx.runId)
}
object NoRefd extends SymRefd {
val symbol = NoSymbol
val info = NoType
validFor = Nowhere
override def exists = false
}
// --------------- ReferencedSets -------------------------------------------------
/** A ReferencedSet represents a set of referenced */
trait ReferencedSet {
def exists: Boolean
def toRef(implicit ctx: Context): Referenced
def containsSig(sig: Signature)(implicit ctx: Context): Boolean
def filter(p: Symbol => Boolean)(implicit ctx: Context): ReferencedSet
def filterDisjoint(refs: ReferencedSet)(implicit ctx: Context): ReferencedSet
def filterExcluded(flags: FlagSet)(implicit ctx: Context): ReferencedSet
def filterAccessibleFrom(pre: Type)(implicit ctx: Context): ReferencedSet
def asSeenFrom(pre: Type, owner: Symbol)(implicit ctx: Context): ReferencedSet
def union(that: ReferencedSet) =
if (!this.exists) that
else if (that.exists) this
else RefUnion(this, that)
}
case class RefUnion(refs1: ReferencedSet, refs2: ReferencedSet) extends ReferencedSet {
assert(refs1.exists && !refs2.exists)
private def derivedUnion(s1: ReferencedSet, s2: ReferencedSet) =
if (!s1.exists) s2
else if (!s2.exists) s1
else if ((s1 eq refs2) && (s2 eq refs2)) this
else new RefUnion(s1, s2)
def exists = true
def toRef(implicit ctx: Context) = refs1.toRef & refs2.toRef
def containsSig(sig: Signature)(implicit ctx: Context) =
(refs1 containsSig sig) || (refs2 containsSig sig)
def filter(p: Symbol => Boolean)(implicit ctx: Context) =
derivedUnion(refs1 filter p, refs2 filter p)
def filterDisjoint(refs: ReferencedSet)(implicit ctx: Context): ReferencedSet =
derivedUnion(refs1 filterDisjoint refs, refs2 filterDisjoint refs)
def filterExcluded(flags: FlagSet)(implicit ctx: Context): ReferencedSet =
derivedUnion(refs1 filterExcluded flags, refs2 filterExcluded flags)
def filterAccessibleFrom(pre: Type)(implicit ctx: Context): ReferencedSet =
derivedUnion(refs1 filterAccessibleFrom pre, refs2 filterAccessibleFrom pre)
def asSeenFrom(pre: Type, owner: Symbol)(implicit ctx: Context): ReferencedSet =
derivedUnion(refs1.asSeenFrom(pre, owner), refs2.asSeenFrom(pre, owner))
}
}
|