diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 4869375d8c94..d63147e80a27 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -109,6 +109,12 @@ object Types extends TypeUtils { /** A cache indicating whether the type was still provisional, last time we checked */ @sharable private var mightBeProvisional = true + // The provisonal state of a type stores the parts which could be changed and + // their info at a given point. + // For example, a `TypeVar` is provisional until it is permanently instantiated, + // and its info is the current instantiation. + type ProvisionalState = util.HashMap[Type, Type] | Null + /** Is this type still provisional? This is the case if the type contains, or depends on, * uninstantiated type variables or type symbols that have the Provisional flag set. * This is an antimonotonic property - once a type is not provisional, it stays so forever. @@ -120,13 +126,28 @@ object Types extends TypeUtils { */ def isProvisional(using Context): Boolean = mightBeProvisional && currentProvisionalState != null - // The provisonal state of a type stores the parts which might be changed and their - // info at a given point. - // For example, a `TypeVar` is provisional until it is permently instantiated, - // and its info is the current instantiation. - type ProvisionalState = util.HashMap[Type, Type] | Null + private var myCurrentProvisionalState: ProvisionalState = null + + private def isCurrentProvisionalStateValid(using Context): Boolean = + myCurrentProvisionalState != null + && myCurrentProvisionalState.uncheckedNN.iterator.forall: (tp, info) => + tp.mightBeProvisional && tp.match + case tp: TypeRef => + if tp.currentSymbol.isProvisional then tp eq info + else !tp.currentSymbol.isStatic && (tp.denot.infoOrCompleter eq info) + case tp: TypeVar => + !tp.isPermanentlyInstantiated + && { + val inst = tp.instanceOpt + if inst.exists then inst eq info + else tp eq info + } + case tp: LazyRef => + !tp.completed && (tp eq info) + case _ => false def currentProvisionalState(using Context): ProvisionalState = + if isCurrentProvisionalStateValid then return myCurrentProvisionalState var state: ProvisionalState = null inline def record(tp: Type, info: Type): Unit = if state == null then state = util.HashMap() @@ -197,6 +218,7 @@ object Types extends TypeUtils { t.mightBeProvisional end test test(this, null) + myCurrentProvisionalState = state state end currentProvisionalState