Skip to content

Commit b762b35

Browse files
committed
Cache Type#isStable (experiment)
1 parent 19d74d1 commit b762b35

File tree

1 file changed

+16
-16
lines changed

1 file changed

+16
-16
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ object Types {
100100
// }
101101

102102
/** A cache indicating whether the type was still provisional, last time we checked */
103-
@sharable private var mightBeProvisional = true
103+
@sharable private var mightBeProvisional: Boolean = true
104+
105+
@sharable private var myIsStable: Byte = 0
104106

105107
/** Is this type still provisional? This is the case if the type contains, or depends on,
106108
* uninstantiated type variables or type symbols that have the Provisional flag set.
@@ -160,12 +162,20 @@ object Types {
160162
* Like in isStableMember, "stability" means idempotence.
161163
* Rationale: If an expression has a stable type, the expression must be idempotent, so stable types
162164
* must be singleton types of stable expressions. */
163-
final def isStable(using Context): Boolean = stripTypeVar match {
165+
final def isStable(using Context): Boolean =
166+
if myIsStable == 0 then
167+
val isStable = computeIsStable()
168+
if !isProvisional then
169+
myIsStable = if isStable then 1 else -1
170+
isStable
171+
else
172+
myIsStable > 0
173+
174+
private final def computeIsStable()(using Context): Boolean = stripTypeVar match
164175
case tp: TermRef => tp.symbol.isStableMember && tp.prefix.isStable || tp.info.isStable
165176
case _: SingletonType | NoPrefix => true
166177
case tp: RefinedOrRecType => tp.parent.isStable
167178
case tp: ExprType => tp.resultType.isStable
168-
case tp: AppliedType => tp.appliedTypeIsStable
169179
case tp: AnnotatedType =>
170180
// NOTE UncheckedStableAnnot was originally meant to be put on fields,
171181
// not on types. Allowing it on types is a Scala 3 extension. See:
@@ -176,8 +186,10 @@ object Types {
176186
// see: tests/explicit-nulls/pos/flow-stable.scala.disabled
177187
tp.tp1.isStable && (realizability(tp.tp2) eq Realizable) ||
178188
tp.tp2.isStable && (realizability(tp.tp1) eq Realizable)
189+
case tp: AppliedType => tp.tycon match
190+
case tycon: TypeRef => defn.isCompiletimeAppliedType(tycon.symbol) && tp.args.forall(_.isStable)
191+
case _ => false
179192
case _ => false
180-
}
181193

182194
/** Is this type a (possibly refined or applied or aliased) type reference
183195
* to the given type symbol?
@@ -4161,23 +4173,11 @@ object Types {
41614173
// Boolean caches: 0 = uninitialized, -1 = false, 1 = true
41624174
private var myStableHash: Byte = 0
41634175
private var myGround: Byte = 0
4164-
private var myIsStable: Byte = 0
4165-
41664176

41674177
def isGround(acc: TypeAccumulator[Boolean])(using Context): Boolean =
41684178
if myGround == 0 then myGround = if acc.foldOver(true, this) then 1 else -1
41694179
myGround > 0
41704180

4171-
inline def appliedTypeIsStable(using Context): Boolean =
4172-
if myIsStable == 0 then
4173-
val isStable: Byte = tycon match
4174-
case tycon: TypeRef if defn.isCompiletimeAppliedType(tycon.symbol) && args.forall(_.isStable) => 1
4175-
case _ => -1
4176-
if !isProvisional then myIsStable = isStable
4177-
isStable > 0
4178-
else
4179-
myIsStable > 0
4180-
41814181
override def underlying(using Context): Type = tycon
41824182

41834183
override def superType(using Context): Type =

0 commit comments

Comments
 (0)