@@ -118,14 +118,20 @@ object Types extends TypeUtils {
118
118
* a call to `resetInst`. This means all caches that rely on `isProvisional`
119
119
* can likely end up returning stale results.
120
120
*/
121
- // def isProvisional(using Context): Boolean = mightBeProvisional && testProvisional
122
- def isProvisional (using Context ): Boolean = mightBeProvisional && ! currentProvisionalState.isEmpty
121
+ def isProvisional (using Context ): Boolean = mightBeProvisional && currentProvisionalState != null
123
122
124
- type ProvisionalState = util.HashMap [Type , Type ]
123
+ // The provisonal state of a type stores the parts which might be changed and their
124
+ // info at a given point.
125
+ // For example, a `TypeVar` is provisional until it is permently instantiated,
126
+ // and its info is the current instantiation.
127
+ type ProvisionalState = util.HashMap [Type , Type ] | Null
125
128
126
129
def currentProvisionalState (using Context ): ProvisionalState =
127
- val state : ProvisionalState = util.HashMap ()
128
- // Compared to `testProvisional`, we don't use short-circuiting or,
130
+ var state : ProvisionalState = null
131
+ inline def record (tp : Type , info : Type ): Unit =
132
+ if state == null then state = util.HashMap ()
133
+ state.uncheckedNN(tp) = info
134
+ // Compared to previous `testProvisional`, we don't use short-circuiting or (`||`),
129
135
// because we want to collect all provisional types.
130
136
class ProAcc extends TypeAccumulator [Boolean ]:
131
137
override def apply (x : Boolean , t : Type ) = x | test(t, this )
@@ -137,7 +143,7 @@ object Types extends TypeUtils {
137
143
// When t is a TypeRef and its symbol is provisional,
138
144
// t will be considered provisional and its state is always updating.
139
145
// We store itself as info.
140
- state(t) = t
146
+ record(t, t)
141
147
true
142
148
else if ! t.currentSymbol.isStatic then
143
149
(t : Type ).mightBeProvisional = false // break cycles
@@ -147,7 +153,7 @@ object Types extends TypeUtils {
147
153
true
148
154
else t.denot.infoOrCompleter.match
149
155
case info : LazyType =>
150
- state(t) = info
156
+ record(t, info)
151
157
true
152
158
case info : AliasingBounds =>
153
159
test(info.alias, theAcc)
@@ -170,18 +176,18 @@ object Types extends TypeUtils {
170
176
if inst.exists then
171
177
// We want to store the temporary instance to the state
172
178
// in order to reuse the cache when possible.
173
- state(t) = inst
179
+ record(t, inst)
174
180
test(inst, theAcc)
175
181
else
176
- // When t is a TypeVar and does not have an instancication ,
182
+ // When t is a TypeVar and does not have an instantiation ,
177
183
// we store itself as info.
178
- state(t) = t
184
+ record(t, t)
179
185
true
180
186
case t : LazyRef =>
181
187
if ! t.completed then
182
188
// When t is a LazyRef and is not completed,
183
189
// we store itself as info.
184
- state(t) = t
190
+ record(t, t)
185
191
true
186
192
else
187
193
test(t.ref, theAcc)
@@ -196,48 +202,17 @@ object Types extends TypeUtils {
196
202
197
203
def isStateUpToDate (
198
204
currentState : ProvisionalState ,
199
- lastState : ProvisionalState | Null )
205
+ lastState : ProvisionalState )
200
206
(using Context ): Boolean =
201
- lastState != null
202
- && currentState.size == lastState.size
203
- && currentState.iterator.forall: (tp, info) =>
204
- lastState.contains(tp) && {
205
- tp match
206
- case tp : TypeRef => (info ne tp) && (info eq lastState(tp))
207
- case _=> info eq lastState(tp)
208
- }
209
-
210
- // private def testProvisional(using Context): Boolean =
211
- // class ProAcc extends TypeAccumulator[Boolean]:
212
- // override def apply(x: Boolean, t: Type) = x || test(t, this)
213
- // def test(t: Type, theAcc: TypeAccumulator[Boolean] | Null): Boolean =
214
- // if t.mightBeProvisional then
215
- // t.mightBeProvisional = t match
216
- // case t: TypeRef =>
217
- // t.currentSymbol.isProvisional || !t.currentSymbol.isStatic && {
218
- // (t: Type).mightBeProvisional = false // break cycles
219
- // test(t.prefix, theAcc)
220
- // || t.denot.infoOrCompleter.match
221
- // case info: LazyType => true
222
- // case info: AliasingBounds => test(info.alias, theAcc)
223
- // case TypeBounds(lo, hi) => test(lo, theAcc) || test(hi, theAcc)
224
- // case _ => false
225
- // }
226
- // case t: TermRef =>
227
- // !t.currentSymbol.isStatic && test(t.prefix, theAcc)
228
- // case t: AppliedType =>
229
- // t.fold(false, (x, tp) => x || test(tp, theAcc))
230
- // case t: TypeVar =>
231
- // !t.isPermanentlyInstantiated || test(t.permanentInst, theAcc)
232
- // case t: LazyRef =>
233
- // !t.completed || test(t.ref, theAcc)
234
- // case _ =>
235
- // (if theAcc != null then theAcc else ProAcc()).foldOver(false, t)
236
- // end if
237
- // t.mightBeProvisional
238
- // end test
239
- // test(this, null)
240
- // end testProvisional
207
+ (currentState eq lastState)
208
+ || currentState != null && lastState != null
209
+ && currentState.size == lastState.size
210
+ && currentState.iterator.forall: (tp, info) =>
211
+ lastState.contains(tp) && {
212
+ tp match
213
+ case tp : TypeRef => (info ne tp) && (info eq lastState(tp))
214
+ case _ => info eq lastState(tp)
215
+ }
241
216
242
217
/** Is this type different from NoType? */
243
218
final def exists : Boolean = this .ne(NoType )
@@ -1398,8 +1373,6 @@ object Types extends TypeUtils {
1398
1373
final def widen (using Context ): Type = this match
1399
1374
case _ : TypeRef | _ : MethodOrPoly => this // fast path for most frequent cases
1400
1375
case tp : TermRef => // fast path for next most frequent case
1401
- // Don't call `isOverloaded` and `underlying` on `tp` directly,
1402
- // to avoid computing provisional state twice.
1403
1376
val denot = tp.denot
1404
1377
if denot.isOverloaded then tp else denot.info.widen
1405
1378
case tp : SingletonType => tp.underlying.widen
@@ -1414,10 +1387,12 @@ object Types extends TypeUtils {
1414
1387
/** Widen from singleton type to its underlying non-singleton
1415
1388
* base type by applying one or more `underlying` dereferences.
1416
1389
*/
1417
- final def widenSingleton (using Context ): Type = stripped match {
1418
- case tp : SingletonType if ! tp.isOverloaded => tp.underlying.widenSingleton
1390
+ final def widenSingleton (using Context ): Type = stripped match
1391
+ case tp : TermRef =>
1392
+ val denot = tp.denot
1393
+ if denot.isOverloaded then this else denot.info.widenSingleton
1394
+ case tp : SingletonType => tp.underlying.widenSingleton
1419
1395
case _ => this
1420
- }
1421
1396
1422
1397
/** Widen from TermRef to its underlying non-termref
1423
1398
* base type, while also skipping Expr types.
@@ -2395,12 +2370,12 @@ object Types extends TypeUtils {
2395
2370
2396
2371
private var myName : Name | Null = null
2397
2372
private var lastDenotation : Denotation | Null = null
2398
- private var lastDenotationProvState : ProvisionalState | Null = null
2373
+ private var lastDenotationProvState : ProvisionalState = null
2399
2374
private var lastSymbol : Symbol | Null = null
2400
2375
private var checkedPeriod : Period = Nowhere
2401
2376
private var myStableHash : Byte = 0
2402
2377
private var mySignature : Signature = uninitialized
2403
- private var mySignatureProvState : ProvisionalState | Null = null
2378
+ private var mySignatureProvState : ProvisionalState = null
2404
2379
private var mySignatureRunId : Int = NoRunId
2405
2380
2406
2381
// Invariants:
@@ -2473,7 +2448,9 @@ object Types extends TypeUtils {
2473
2448
final def symbol (using Context ): Symbol =
2474
2449
// We can rely on checkedPeriod (unlike in the definition of `denot` below)
2475
2450
// because SymDenotation#installAfter never changes the symbol
2476
- if (checkedPeriod.code == ctx.period.code) lastSymbol.asInstanceOf [Symbol ]
2451
+ if checkedPeriod.code == ctx.period.code
2452
+ && isStateUpToDate(prefix.currentProvisionalState, lastDenotationProvState) then
2453
+ lastSymbol.asInstanceOf [Symbol ]
2477
2454
else computeSymbol
2478
2455
2479
2456
private def computeSymbol (using Context ): Symbol =
@@ -2482,7 +2459,6 @@ object Types extends TypeUtils {
2482
2459
if (sym.isValidInCurrentRun) sym else denot.symbol
2483
2460
case name =>
2484
2461
(if (denotationIsCurrent) lastDenotation.asInstanceOf [Denotation ] else denot).symbol
2485
- if checkedPeriod.code != NowhereCode then checkedPeriod = ctx.period
2486
2462
result
2487
2463
2488
2464
/** There is a denotation computed which is valid (somewhere in) the
@@ -2532,8 +2508,8 @@ object Types extends TypeUtils {
2532
2508
// Even if checkedPeriod == now we still need to recheck lastDenotation.validFor
2533
2509
// as it may have been mutated by SymDenotation#installAfter
2534
2510
if checkedPeriod.code != NowhereCode
2535
- && isStateUpToDate(prefix.currentProvisionalState, lastDenotationProvState)
2536
2511
&& lastd.validFor.contains(ctx.period)
2512
+ && isStateUpToDate(prefix.currentProvisionalState, lastDenotationProvState)
2537
2513
then lastd
2538
2514
else computeDenot
2539
2515
@@ -3959,13 +3935,13 @@ object Types extends TypeUtils {
3959
3935
// (3) myScala2SignatureRunId != NoRunId => myScala2Signature != null
3960
3936
3961
3937
private var mySignature : Signature = uninitialized
3962
- private var mySignatureProvState : ProvisionalState | Null = null
3938
+ private var mySignatureProvState : ProvisionalState = null
3963
3939
private var mySignatureRunId : Int = NoRunId
3964
3940
private var myJavaSignature : Signature = uninitialized
3965
- private var myJavaSignatureProvState : ProvisionalState | Null = null
3941
+ private var myJavaSignatureProvState : ProvisionalState = null
3966
3942
private var myJavaSignatureRunId : Int = NoRunId
3967
3943
private var myScala2Signature : Signature = uninitialized
3968
- private var myScala2SignatureProvState : ProvisionalState | Null = null
3944
+ private var myScala2SignatureProvState : ProvisionalState = null
3969
3945
private var myScala2SignatureRunId : Int = NoRunId
3970
3946
3971
3947
/** If `isJava` is false, the Scala signature of this method. Otherwise, its Java signature.
0 commit comments