[FIR] avoid jumping from super type transformer for local classes to unresolved non-local classes
In the worst case, we will visit the entire hierarchy of a local class, where non-local classes are not yet resolved ^KT-56550
This commit is contained in:
committed by
Space Team
parent
6f584bcbe7
commit
ee74e10f28
+45
-9
@@ -43,6 +43,8 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.types.model.TypeArgumentMarker
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
|
||||
class FirSupertypeResolverProcessor(session: FirSession, scopeSession: ScopeSession) : FirTransformerBasedResolveProcessor(
|
||||
session, scopeSession, FirResolvePhase.SUPER_TYPES
|
||||
@@ -81,7 +83,7 @@ fun <F : FirClassLikeDeclaration> F.runSupertypeResolvePhaseForLocalClass(
|
||||
useSiteFile: FirFile,
|
||||
containingDeclarations: List<FirDeclaration>,
|
||||
): F {
|
||||
val supertypeComputationSession = SupertypeComputationSession()
|
||||
val supertypeComputationSession = SupertypeComputationSessionForLocalClasses()
|
||||
val supertypeResolverVisitor = FirSupertypeResolverVisitor(
|
||||
session, supertypeComputationSession, scopeSession,
|
||||
currentScopeList.toPersistentList(),
|
||||
@@ -97,6 +99,41 @@ fun <F : FirClassLikeDeclaration> F.runSupertypeResolvePhaseForLocalClass(
|
||||
return this.transform<F, Nothing?>(applySupertypesTransformer, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* We should resolve non-local classes to [FirResolvePhase.SUPER_TYPES] explicitly
|
||||
* to avoid unsafe access to unresolved super type references
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* open class TopLevelClass
|
||||
* open class AnotherTopLevelClass : TopLevelClass()
|
||||
*
|
||||
* fun resolveMe() {
|
||||
* class LocalClass : AnotherTopLevelClass() {
|
||||
* class NestedLocalClass
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* During the resolution of local classes, in the best case, we will only try
|
||||
* to access the unresolved super type reference of "AnotherTopLevelClass" that is unsafe in the context of parallel resolution.
|
||||
* In the worst case, from NestedLocalClass we will visit the entire hierarchy of "LocalClass"
|
||||
*/
|
||||
private class SupertypeComputationSessionForLocalClasses : SupertypeComputationSession() {
|
||||
override fun getResolvedSuperTypeRefsForOutOfSessionDeclaration(classLikeDeclaration: FirClassLikeDeclaration): List<FirResolvedTypeRef>? {
|
||||
classLikeDeclaration.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES)
|
||||
return super.getResolvedSuperTypeRefsForOutOfSessionDeclaration(classLikeDeclaration)
|
||||
}
|
||||
|
||||
override fun supertypeRefs(declaration: FirClassLikeDeclaration): List<FirTypeRef> {
|
||||
if (!declaration.isLocal) {
|
||||
declaration.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES)
|
||||
}
|
||||
|
||||
return super.supertypeRefs(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
private class FirApplySupertypesTransformer(
|
||||
private val supertypeComputationSession: SupertypeComputationSession,
|
||||
private val session: FirSession,
|
||||
@@ -285,16 +322,10 @@ class FirSupertypeResolverVisitor(
|
||||
if (supertype !is ConeClassLikeType) continue
|
||||
val supertypeModuleSession = supertype.toSymbol(session)?.moduleData?.session ?: continue
|
||||
val fir = supertype.lookupTag.toSymbol(supertypeModuleSession)?.fir ?: continue
|
||||
resolveAllSupertypes(fir, fir.supertypeRefs(), visited)
|
||||
resolveAllSupertypes(fir, supertypeComputationSession.supertypeRefs(fir), visited)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirClassLikeDeclaration.supertypeRefs() = when (this) {
|
||||
is FirRegularClass -> superTypeRefs
|
||||
is FirTypeAlias -> listOf(expandedTypeRef)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
private fun prepareScopes(classLikeDeclaration: FirClassLikeDeclaration): PersistentList<FirScope> {
|
||||
val classId = classLikeDeclaration.symbol.classId
|
||||
val classModuleSession = classLikeDeclaration.moduleData.session
|
||||
@@ -580,6 +611,12 @@ open class SupertypeComputationSession {
|
||||
else -> null
|
||||
}
|
||||
|
||||
internal open fun supertypeRefs(declaration: FirClassLikeDeclaration): List<FirTypeRef> = when (declaration) {
|
||||
is FirRegularClass -> declaration.superTypeRefs
|
||||
is FirTypeAlias -> listOf(declaration.expandedTypeRef)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
/**
|
||||
* @param declaration declaration to be checked for loops
|
||||
* @param visited visited declarations during the current loop search
|
||||
@@ -725,7 +762,6 @@ open class SupertypeComputationSession {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sealed class SupertypeComputationStatus {
|
||||
object NotComputed : SupertypeComputationStatus()
|
||||
object Computing : SupertypeComputationStatus()
|
||||
|
||||
Reference in New Issue
Block a user