From c2b09d3b1e7c7b46ed8680c5fd98f0ac728d986e Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Tue, 2 May 2023 19:30:55 +0200 Subject: [PATCH] [LL FIR] rewrite LLFirSuperTypeTargetResolver The previous implementation had issues with locks, publication and performance Also, this change fixed a problem with mixed cycle inheritance ^KT-56550 ^KTIJ-25430 Fixed ^KTIJ-23520 Fixed ^KT-57623 Fixed ^KTIJ-25372 Fixed ^KT-58357 Fixed --- .../KtFirNamedClassOrObjectSymbolBase.kt | 2 +- .../fir/symbols/KtFirTypeAndAnnotations.kt | 17 +- .../LLFirSupertypeLazyResolver.kt | 431 ++++++++++-------- .../testdata/lazyResolve/cyclicHierarchy.kt | 6 + .../testdata/lazyResolve/cyclicHierarchy.txt | 223 +++++++++ .../testdata/lazyResolve/cyclicHierarchy2.kt | 6 + .../testdata/lazyResolve/cyclicHierarchy2.txt | 223 +++++++++ .../testdata/lazyResolve/cyclicHierarchy3.kt | 8 + .../testdata/lazyResolve/cyclicHierarchy3.txt | 279 ++++++++++++ .../lazyResolve/cyclicNestedHierarchy.kt | 4 + .../lazyResolve/cyclicNestedHierarchy.txt | 321 +++++++++++++ .../lazyResolve/cyclicNestedHierarchy2.kt | 4 + .../lazyResolve/cyclicNestedHierarchy2.txt | 321 +++++++++++++ ...otLazyDeclarationResolveTestGenerated.java | 30 ++ ...ceLazyDeclarationResolveTestGenerated.java | 30 ++ .../kotlin/fir/java/FirJavaElementFinder.kt | 13 +- .../transformers/FirSupertypesResolution.kt | 220 +++++---- .../kotlinJavaKotlinCycle.reversed.kt | 20 - ...eversed.kt => kotlinJavaNestedCycle.ll.kt} | 3 + 19 files changed, 1844 insertions(+), 317 deletions(-) create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.kt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.txt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.kt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.txt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.kt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.txt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.kt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.txt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.kt create mode 100644 analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.txt delete mode 100644 compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaKotlinCycle.reversed.kt rename compiler/testData/diagnostics/tests/cyclicHierarchy/{kotlinJavaNestedCycle.reversed.kt => kotlinJavaNestedCycle.ll.kt} (72%) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbolBase.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbolBase.kt index 0be92f02a8b..c74dabc67cf 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbolBase.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirNamedClassOrObjectSymbolBase.kt @@ -53,7 +53,7 @@ internal sealed class KtFirNamedClassOrObjectSymbolBase : KtNamedClassOrObjectSy // Shared Operations //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override val superTypes: List by cached { - firSymbol.superTypesAndAnnotationsListForRegularClass(builder) + firSymbol.superTypesList(builder) } context(KtAnalysisSession) diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeAndAnnotations.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeAndAnnotations.kt index 94d1d3a0178..9c7c2106262 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeAndAnnotations.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/symbols/KtFirTypeAndAnnotations.kt @@ -8,26 +8,11 @@ package org.jetbrains.kotlin.analysis.api.fir.symbols import org.jetbrains.kotlin.analysis.api.fir.KtSymbolByFirBuilder import org.jetbrains.kotlin.analysis.api.symbols.KtReceiverParameterSymbol import org.jetbrains.kotlin.analysis.api.types.KtType -import org.jetbrains.kotlin.fir.declarations.FirResolvePhase -import org.jetbrains.kotlin.fir.resolve.transformers.resolveSupertypesInTheAir import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.types.FirTypeRef -import org.jetbrains.kotlin.fir.declarations.resolvePhase -internal fun FirClassSymbol<*>.superTypesList(builder: KtSymbolByFirBuilder): List = - resolvedSuperTypeRefs.mapToKtType(builder) - -internal fun FirRegularClassSymbol.superTypesAndAnnotationsListForRegularClass(builder: KtSymbolByFirBuilder): List { - val fir = fir - - if (fir.resolvePhase >= FirResolvePhase.SUPER_TYPES) { - return fir.superTypeRefs.mapToKtType(builder) - } - - return fir.resolveSupertypesInTheAir(builder.rootSession).mapToKtType(builder) -} +internal fun FirClassSymbol<*>.superTypesList(builder: KtSymbolByFirBuilder): List = resolvedSuperTypeRefs.mapToKtType(builder) private fun List.mapToKtType( builder: KtSymbolByFirBuilder, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt index 51b124410de..2bd113820ca 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt @@ -5,36 +5,31 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignation -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithFile -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignation import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.asResolveTarget +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.tryCollectDesignationWithFile import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.LLFirPhaseUpdater -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirResolvableSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkTypeRefIsResolved -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.withInvalidationOnException -import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElementWithResolveState import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic +import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass -import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.resolve.ScopeSession -import org.jetbrains.kotlin.fir.resolve.transformers.FirApplySupertypesTransformer +import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.transformers.FirSupertypeResolverVisitor import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationSession import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationStatus import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector +import org.jetbrains.kotlin.fir.resolve.transformers.platformSupertypeUpdater +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase -import org.jetbrains.kotlin.fir.types.ConeClassLikeType -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.toSymbol -import org.jetbrains.kotlin.fir.types.type -import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer -import org.jetbrains.kotlin.fir.visitors.FirVisitor +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.name.ClassId internal object LLFirSupertypeLazyResolver : LLFirLazyResolver(FirResolvePhase.SUPER_TYPES) { override fun resolve( @@ -70,14 +65,19 @@ internal object LLFirSupertypeLazyResolver : LLFirLazyResolver(FirResolvePhase.S } } -internal class LLFirSuperTypeTargetResolver( +private class LLFirSuperTypeTargetResolver( target: LLFirResolveTarget, lockProvider: LLFirLockProvider, private val session: FirSession, private val scopeSession: ScopeSession, + private val supertypeComputationSession: LLFirSupertypeComputationSession = LLFirSupertypeComputationSession(session), + private val visitedElements: MutableSet = hashSetOf(), ) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.SUPER_TYPES, isJumpingPhase = true) { - - private val supertypeComputationSession = SupertypeComputationSession() + private val supertypeResolver = FirSupertypeResolverVisitor( + session = session, + supertypeComputationSession = supertypeComputationSession, + scopeSession = scopeSession, + ) override fun withFile(firFile: FirFile, action: () -> Unit) { action() @@ -85,203 +85,256 @@ internal class LLFirSuperTypeTargetResolver( @Deprecated("Should never be called directly, only for override purposes, please use withRegularClass", level = DeprecationLevel.ERROR) override fun withRegularClassImpl(firClass: FirRegularClass, action: () -> Unit) { - doResolveWithoutLock(firClass) - action() + supertypeResolver.withClass(firClass) { + doResolveWithoutLock(firClass) + action() + } } override fun doResolveWithoutLock(target: FirElementWithResolveState): Boolean { + val isVisited = !visitedElements.add(target) + if (isVisited) return true + when (target) { - is FirRegularClass, is FirTypeAlias -> { - val designationToResolve = FirDesignationWithFile(nestedClassesStack, target, resolveTarget.firFile) - val collected = collect(designationToResolve) - supertypeComputationSession.breakLoops(session) - apply(collected) - } - else -> { - performCustomResolveUnderLock(target) { - // just update the phase - } + is FirRegularClass -> performResolve( + declaration = target, + resolver = { target.resolveSupertypeRefs() }, + superTypeUpdater = { + target.replaceSuperTypeRefs(it) + session.platformSupertypeUpdater?.updateSupertypesIfNeeded(target, scopeSession) + }, + ) + is FirTypeAlias -> performResolve( + declaration = target, + resolver = { target.resolveExpandedTypeRef() }, + superTypeUpdater = { target.replaceExpandedTypeRef(it.single()) }, + ) + else -> performCustomResolveUnderLock(target) { + // just update the phase } } + return true } + private fun FirRegularClass.resolveSupertypeRefs(): List { + val superTypeRefs = superTypeRefs + /** + * TODO: KT-56551 this is safe, because we have a global phase lock + * Without such lock we should make a copy of [superTypeRefs] under a lock or + * FirRegularClassImpl should have "var superTypeRefs" + assign instead of "val superTypeRefs" + mutation + */ + return supertypeResolver.resolveSpecificClassLikeSupertypes(this, superTypeRefs) + } + + private fun FirTypeAlias.resolveExpandedTypeRef(): List { + val expandedTypeRef = expandedTypeRef + return supertypeResolver.resolveTypeAliasSupertype(this, expandedTypeRef) + } + + private inline fun performResolve( + declaration: T, + resolver: () -> List, + crossinline superTypeUpdater: (List) -> Unit, + ) { + // To avoid redundant work, because a publication won't be executed + if (declaration.resolvePhase >= resolverPhase) return + + declaration.lazyResolveToPhase(resolverPhase.previous) + + // 1. Resolve declaration super type refs + val resolvedSuperTypeRefs = resolver() + + // 2. Resolve super declarations + val status = supertypeComputationSession.getSupertypesComputationStatus(declaration) + if (status is SupertypeComputationStatus.Computed) { + for (computedType in status.supertypeRefs) { + crawlSupertype(computedType.type) + } + } + + // 3. Find loops + val loopedSuperTypeRefs = supertypeComputationSession.findLoopFor(declaration) + + // 4. Get error type refs or already resolved + val resultedTypeRefs = loopedSuperTypeRefs ?: resolvedSuperTypeRefs + + // 5. Publish the result + performCustomResolveUnderLock(declaration) { + superTypeUpdater(resultedTypeRefs) + } + } + + /** + * We want to apply resolved supertypes to as many designations as possible. + * So we crawl the resolved supertypes of visited designations to find more designations to collect. + */ + private fun crawlSupertype(type: ConeKotlinType) { + val classLikeDeclaration = type.toSymbol(session)?.fir + if (classLikeDeclaration !is FirClassLikeDeclaration) return + if (classLikeDeclaration in visitedElements) return + if (classLikeDeclaration is FirJavaClass) { + if (!classLikeDeclaration.canHaveLoopInSupertypesHierarchy(session)) return + + visitedElements += classLikeDeclaration + val parentClass = classLikeDeclaration.outerClass(session) + if (parentClass != null) { + crawlSupertype(parentClass.defaultType()) + } + + classLikeDeclaration.superTypeRefs.filterIsInstance().forEach { + crawlSupertype(it.type) + } + + return + } + + val resolveTarget = classLikeDeclaration.takeIf { it.canHaveLoopInSupertypesHierarchy(session, forceSkipResolvedClasses = true) } + ?.tryCollectDesignationWithFile() + ?.asResolveTarget() + + if (resolveTarget != null) { + LLFirSuperTypeTargetResolver( + target = resolveTarget, + lockProvider = lockProvider, + session = session, + scopeSession = scopeSession, + supertypeComputationSession = supertypeComputationSession, + visitedElements = visitedElements, + ).resolveDesignation() + + LLFirLazyPhaseResolverByPhase.getByPhase(resolverPhase).checkIsResolved(resolveTarget) + } else if (type is ConeClassLikeType) { + // The `classLikeDeclaration` is not associated with a file, and thus there is no need to resolve it, but it may still point + // to declarations via its type arguments which need to be collected and have a containing file. + // For example, a `Function1` could point to a type alias. + type.typeArguments.forEach { it.type?.let(::crawlSupertype) } + } + } + override fun doLazyResolveUnderLock(target: FirElementWithResolveState) { error("Should be resolved without lock in ${::doResolveWithoutLock.name}") } +} - private inner class DesignatedFirSupertypeResolverVisitor(classDesignation: FirDesignation) : - FirSupertypeResolverVisitor( +/** + * We shouldn't skip Java source classes because they're marked as BODY_RESOLVE, + * but this doesn't give us knowledge about its participation in the calculation of supertypes. + * The contract here – if a declaration is already resolved to FirResolvePhase.SUPER_TYPES or higher that this + * means that this class can't have loop with our class, because in this case this declaration will be present + * in the current supertypes resolve session + */ +private fun FirClassLikeDeclaration.canHaveLoopInSupertypesHierarchy( + session: FirSession, + forceSkipResolvedClasses: Boolean = false, +): Boolean = when { + this is FirJavaClass -> origin is FirDeclarationOrigin.Java.Source + resolvePhase < FirResolvePhase.SUPER_TYPES -> true + + // We should still process resolved if it has loop in super type refs, because we can be part of this cycle + !forceSkipResolvedClasses && this is FirRegularClass -> hasLoopInSupertypeRefs(session) + else -> false +} + +private fun FirRegularClass.outerClass(session: FirSession): FirRegularClass? = symbol.classId.parentClassId?.let { parentClassId -> + session.symbolProvider.getClassLikeSymbolByClassId(parentClassId)?.fir as? FirRegularClass +} + +/** + * The class must be already resolved + */ +private fun FirRegularClass.hasLoopInSupertypeRefs(session: FirSession): Boolean { + if (superTypeRefs.any(FirTypeRef::isLoopedSupertypeRef)) { + return true + } + + return outerClass(session)?.hasLoopInSupertypeRefs(session) == true +} + +private val FirTypeRef.isLoopedSupertypeRef: Boolean + get() { + if (this !is FirErrorTypeRef) return false + val diagnostic = diagnostic + return diagnostic is ConeSimpleDiagnostic && diagnostic.kind == DiagnosticKind.LoopInSupertype + } + +private class LLFirSupertypeComputationSession(private val session: FirSession) : SupertypeComputationSession() { + /** + * These collections exist to reuse a collection for each search to avoid repeated memory allocation. + * Can be replaced with a new collection on each invocation of [findLoopFor] + */ + private val visited: MutableSet = hashSetOf() + private val looped: MutableSet = hashSetOf() + private val pathSet: MutableSet = hashSetOf() + private val path: MutableList = mutableListOf() + // --------------- + + /** + * Map from [FirClassLikeDeclaration] to [List>], + * where the list contains at least one [FirErrorTypeRef] for looped references + */ + private val updatedTypesForDeclarationsWithLoop: MutableMap> = hashMapOf() + + /** + * @param declaration declaration to be checked for loops + * @return list of resolved super type refs if at least one of them is [FirErrorTypeRef] due to cycle hierarchy + */ + fun findLoopFor(declaration: FirClassLikeDeclaration): List? { + breakLoopFor( + declaration = declaration, session = session, - supertypeComputationSession = supertypeComputationSession, - scopeSession = scopeSession, - scopeForLocalClass = null, - localClassesNavigationInfo = null, - ) { - val declarationTransformer = LLFirDeclarationTransformer(classDesignation) + visited = visited, + looped = looped, + pathSet = pathSet, + path = path, + ) - override fun visitDeclarationContent(declaration: FirDeclaration, data: Any?) { - declarationTransformer.visitDeclarationContent(this, declaration, data) { - super.visitDeclarationContent(declaration, data) - declaration - } - } + require(path.isEmpty()) { "Path should be empty" } + require(pathSet.isEmpty()) { "Path set should be empty" } + visited.clear() + looped.clear() + return updatedTypesForDeclarationsWithLoop[declaration] } - private inner class DesignatedFirApplySupertypesTransformer(classDesignation: FirDesignation) : - FirApplySupertypesTransformer(supertypeComputationSession, session, scopeSession) { - - val declarationTransformer = LLFirDeclarationTransformer(classDesignation) - - override fun transformDeclarationContent(declaration: FirDeclaration, data: Any?): FirDeclaration { - return declarationTransformer.transformDeclarationContent(this, declaration, data) { - super.transformDeclarationContent(declaration, data) - } - } - } - - private inner class DesignationCollector { - private val visited = mutableMapOf() - private val toVisit = mutableListOf() - - fun collect(designation: FirDesignationWithFile): Collection { - toVisit.add(designation) - while (toVisit.isNotEmpty()) { - toVisit.forEach(::visitDesignation) - toVisit.clear() - - // We want to apply resolved supertypes to as many designations as possible. So we crawl the resolved supertypes of visited - // designations to find more designations to collect. - for (supertypeComputationStatus in supertypeComputationSession.supertypeStatusMap.values) { - if (supertypeComputationStatus !is SupertypeComputationStatus.Computed) continue - supertypeComputationStatus.supertypeRefs.forEach { crawlSupertype(it.type) } - } - } - - return visited.values - } - - private fun visitDesignation(designation: FirDesignationWithFile) { - checkCanceled() - val resolver = DesignatedFirSupertypeResolverVisitor(designation) - designation.firFile.lazyResolveToPhase(FirResolvePhase.IMPORTS) - designation.firFile.accept(resolver, null) - resolver.declarationTransformer.ensureDesignationPassed() - visited[designation.target] = designation - } - - private fun crawlSupertype(type: ConeKotlinType) { - val classLikeDeclaration = type.toSymbol(session)?.fir - if (classLikeDeclaration !is FirClassLikeDeclaration) return - if (classLikeDeclaration is FirJavaClass) return - if (visited.containsKey(classLikeDeclaration)) return - - val containingFile = - classLikeDeclaration.llFirResolvableSession?.moduleComponents?.cache?.getContainerFirFile(classLikeDeclaration) - if (containingFile != null) { - toVisit.add(classLikeDeclaration.collectDesignation(containingFile)) - } else if (type is ConeClassLikeType) { - // The `classLikeDeclaration` is not associated with a file and thus there is no need to resolve it, but it may still point - // to declarations via its type arguments which need to be collected and have a containing file. For example, a `Function1` - // could point to a type alias. - type.typeArguments.forEach { it.type?.let(::crawlSupertype) } - } - } + override fun isAlreadyResolved(classLikeDeclaration: FirClassLikeDeclaration): Boolean { + return !classLikeDeclaration.canHaveLoopInSupertypesHierarchy(session) } /** - * Resolves the supertypes of [designation] and collects all designations that resolved supertypes should be applied to, including - * [designation] itself and any designations discovered via resolved supertypes. + * We shouldn't try to iterate over unresolved class. Otherwise, it can lead to [ConcurrentModificationException] */ - private fun collect(designation: FirDesignationWithFile): Collection = - DesignationCollector().collect(designation) + override fun getResolvedSuperTypeRefsForOutOfSessionDeclaration(classLikeDeclaration: FirClassLikeDeclaration): List? { + if (classLikeDeclaration.resolvePhase < FirResolvePhase.SUPER_TYPES) return emptyList() + + return super.getResolvedSuperTypeRefsForOutOfSessionDeclaration(classLikeDeclaration) + } /** - * Applies the resolved supertypes in [supertypeComputationSession] to each designation in [designations]. + * It is possible that one of super type refs were already reported as an error, but the second – not. + * So in this case, we want to save already reported errors and add a new one. + * Example: + * ``` + * interface B : A, ResolveMe {} + * interface C : B {} + * interface D : B {} + * interface ResolveMe : F {} + * // D will be marked as error during ResolveMe->F->D->B->ResolveMe round. + * // And we will back to super type refs of class F during the resolution of class C + * interface F : D, C {} + * interface NonLoopedInterface : C + * ``` */ - private fun apply(designations: Collection) { - fun applyToFileSymbols(designations: List) { - for (designation in designations) { - checkCanceled() - val applier = DesignatedFirApplySupertypesTransformer(designation) - (designation.target as FirDeclaration).lazyResolveToPhase(resolverPhase.previous) - performCustomResolveUnderLock(designation.target) { - designation.firFile.transform(applier, null) - applier.declarationTransformer.ensureDesignationPassed() + override fun reportLoopErrorRefs(classLikeDeclaration: FirClassLikeDeclaration, supertypeRefs: List) { + updatedTypesForDeclarationsWithLoop.merge(classLikeDeclaration, supertypeRefs) { oldRefs, newRefs -> + buildList(oldRefs.size) { + for ((old, new) in oldRefs.zip(newRefs)) { + if (old is FirErrorTypeRef) { + add(old) + } else { + add(new) + } } } } - - val filesToDesignations = designations.groupBy { it.firFile } - for (designationsPerFile in filesToDesignations) { - checkCanceled() - val session = designationsPerFile.key.llFirResolvableSession - ?: error("When FirFile exists for the declaration, the session should be resolvable") - withInvalidationOnException(session) { - applyToFileSymbols(designationsPerFile.value) - } - } - } -} - -private class LLFirDeclarationTransformer(private val designation: FirDesignation) { - private val designationWithoutTargetIterator = designation.toSequence(includeTarget = false).iterator() - private var isInsideTargetDeclaration: Boolean = false - private var designationPassed: Boolean = false - - inline fun visitDeclarationContent( - visitor: FirVisitor, - declaration: FirDeclaration, - data: D, - default: () -> FirDeclaration - ): FirDeclaration = processDeclarationContent(declaration, default) { - it.accept(visitor, data) - } - - inline fun transformDeclarationContent( - transformer: FirDefaultTransformer, - declaration: FirDeclaration, - data: D, - default: () -> FirDeclaration - ): FirDeclaration = processDeclarationContent(declaration, default) { toTransform -> - toTransform.transform(transformer, data).also { transformed -> - check(transformed === toTransform) { - "become $transformed `${transformed.render()}`, was ${toTransform}: `${toTransform.render()}`" - } - } - } - - private inline fun processDeclarationContent( - declaration: FirDeclaration, - default: () -> FirDeclaration, - applyToDesignated: (FirElementWithResolveState) -> Unit, - ): FirDeclaration { - //It means that we are inside the target declaration - if (isInsideTargetDeclaration) { - return default() - } - - //It means that we already transform target declaration and now can skip all others - if (designationPassed) { - return declaration - } - - if (designationWithoutTargetIterator.hasNext()) { - applyToDesignated(designationWithoutTargetIterator.next()) - } else { - try { - isInsideTargetDeclaration = true - designationPassed = true - applyToDesignated(designation.target) - } finally { - isInsideTargetDeclaration = false - } - } - - return declaration - } - - fun ensureDesignationPassed() { - check(designationPassed) { "Designation not passed for declaration ${designation.target::class.simpleName}" } } } diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.kt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.kt new file mode 100644 index 00000000000..7792eac48bc --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.kt @@ -0,0 +1,6 @@ +interface B : A, ResolveMe {} +interface C : B {} +interface D : B {} +interface ResolveMe : F {} +interface F : D, C {} +interface NonLoopedInterface : C \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.txt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.txt new file mode 100644 index 00000000000..86f32d4d9fe --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.txt @@ -0,0 +1,223 @@ +RAW_FIR: +FILE: [ResolvedTo(RAW_FIR)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface B : A, ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface C : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface D : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface ResolveMe : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D, C { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +IMPORTS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface B : A, ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface C : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface D : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface ResolveMe : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D, C { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +COMPILER_REQUIRED_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface B : A, ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface C : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface D : B { + } + public? final? [ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] interface ResolveMe : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D, C { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +COMPANION_GENERATION: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface B : A, ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface C : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface D : B { + } + public? final? [ResolvedTo(COMPANION_GENERATION)] interface ResolveMe : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D, C { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +SUPER_TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /B> { + } + public? final? [ResolvedTo(TYPES)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +STATUS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /B> { + } + public abstract [ResolvedTo(STATUS)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +EXPECT_ACTUAL_MATCHING: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /B> { + } + public abstract [ResolvedTo(EXPECT_ACTUAL_MATCHING)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +ARGUMENTS_OF_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /B> { + } + public abstract [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +CONTRACTS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /B> { + } + public abstract [ResolvedTo(CONTRACTS)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +IMPLICIT_TYPES_BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /B> { + } + public abstract [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +ANNOTATIONS_ARGUMENTS_MAPPING: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /B> { + } + public abstract [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /B> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +FILE RAW TO BODY: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy.kt + [ResolvedTo(BODY_RESOLVE)] annotations container + public abstract [ResolvedTo(BODY_RESOLVE)] interface B : , /ResolveMe> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface C : /B> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface D : /B> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface ResolveMe : /F> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface F : /D>, /C> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface NonLoopedInterface : R|C| { + } diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.kt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.kt new file mode 100644 index 00000000000..be1c022210f --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.kt @@ -0,0 +1,6 @@ +interface ResolveMe : A, E {} +interface C : ResolveMe {} +interface D : ResolveMe {} +interface E : F {} +interface F : D, C {} +interface NonLoopedInterface : C \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.txt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.txt new file mode 100644 index 00000000000..0efa8037ae0 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.txt @@ -0,0 +1,223 @@ +RAW_FIR: +FILE: [ResolvedTo(RAW_FIR)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface ResolveMe : A, E { + } + public? final? [ResolvedTo(RAW_FIR)] interface C : ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface D : ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface E : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D, C { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +IMPORTS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface ResolveMe : A, E { + } + public? final? [ResolvedTo(RAW_FIR)] interface C : ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface D : ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface E : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D, C { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +COMPILER_REQUIRED_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] interface ResolveMe : A, E { + } + public? final? [ResolvedTo(RAW_FIR)] interface C : ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface D : ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface E : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D, C { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +COMPANION_GENERATION: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(COMPANION_GENERATION)] interface ResolveMe : A, E { + } + public? final? [ResolvedTo(RAW_FIR)] interface C : ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface D : ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface E : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D, C { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +SUPER_TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface ResolveMe : , /E> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface E : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(TYPES)] interface ResolveMe : , /E> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface E : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +STATUS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public abstract [ResolvedTo(STATUS)] interface ResolveMe : , /E> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface E : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +EXPECT_ACTUAL_MATCHING: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public abstract [ResolvedTo(EXPECT_ACTUAL_MATCHING)] interface ResolveMe : , /E> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface E : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +ARGUMENTS_OF_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public abstract [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] interface ResolveMe : , /E> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface E : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +CONTRACTS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public abstract [ResolvedTo(CONTRACTS)] interface ResolveMe : , /E> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface E : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +IMPLICIT_TYPES_BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public abstract [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] interface ResolveMe : , /E> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface E : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +ANNOTATIONS_ARGUMENTS_MAPPING: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public abstract [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] interface ResolveMe : , /E> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface E : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public abstract [ResolvedTo(BODY_RESOLVE)] interface ResolveMe : , /E> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D : /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface E : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D>, /C> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C { + } + +FILE RAW TO BODY: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy2.kt + [ResolvedTo(BODY_RESOLVE)] annotations container + public abstract [ResolvedTo(BODY_RESOLVE)] interface ResolveMe : , /E> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface C : /ResolveMe> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface D : /ResolveMe> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface E : /F> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface F : /D>, /C> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface NonLoopedInterface : R|C| { + } diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.kt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.kt new file mode 100644 index 00000000000..0b447893432 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.kt @@ -0,0 +1,8 @@ +interface B : A, ResolveMe {} +interface C1 : B {} +interface C2 : C1 {} +interface D1 : B {} +interface D2 : D1 {} +interface ResolveMe : F {} +interface F : D2, C2 {} +interface NonLoopedInterface : C2 \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.txt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.txt new file mode 100644 index 00000000000..d8480d02785 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.txt @@ -0,0 +1,279 @@ +RAW_FIR: +FILE: [ResolvedTo(RAW_FIR)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface B : A, ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface C1 : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface C2 : C1 { + } + public? final? [ResolvedTo(RAW_FIR)] interface D1 : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface D2 : D1 { + } + public? final? [ResolvedTo(RAW_FIR)] interface ResolveMe : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D2, C2 { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +IMPORTS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface B : A, ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface C1 : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface C2 : C1 { + } + public? final? [ResolvedTo(RAW_FIR)] interface D1 : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface D2 : D1 { + } + public? final? [ResolvedTo(RAW_FIR)] interface ResolveMe : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D2, C2 { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +COMPILER_REQUIRED_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface B : A, ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface C1 : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface C2 : C1 { + } + public? final? [ResolvedTo(RAW_FIR)] interface D1 : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface D2 : D1 { + } + public? final? [ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] interface ResolveMe : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D2, C2 { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +COMPANION_GENERATION: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(RAW_FIR)] interface B : A, ResolveMe { + } + public? final? [ResolvedTo(RAW_FIR)] interface C1 : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface C2 : C1 { + } + public? final? [ResolvedTo(RAW_FIR)] interface D1 : B { + } + public? final? [ResolvedTo(RAW_FIR)] interface D2 : D1 { + } + public? final? [ResolvedTo(COMPANION_GENERATION)] interface ResolveMe : F { + } + public? final? [ResolvedTo(RAW_FIR)] interface F : D2, C2 { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +SUPER_TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C2 : /C1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D2 : /D1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D2>, /C2> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C2 : /C1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D2 : /D1> { + } + public? final? [ResolvedTo(TYPES)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D2>, /C2> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +STATUS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C2 : /C1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D2 : /D1> { + } + public abstract [ResolvedTo(STATUS)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D2>, /C2> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +EXPECT_ACTUAL_MATCHING: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C2 : /C1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D2 : /D1> { + } + public abstract [ResolvedTo(EXPECT_ACTUAL_MATCHING)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D2>, /C2> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +ARGUMENTS_OF_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C2 : /C1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D2 : /D1> { + } + public abstract [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D2>, /C2> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +CONTRACTS: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C2 : /C1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D2 : /D1> { + } + public abstract [ResolvedTo(CONTRACTS)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D2>, /C2> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +IMPLICIT_TYPES_BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C2 : /C1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D2 : /D1> { + } + public abstract [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D2>, /C2> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +ANNOTATIONS_ARGUMENTS_MAPPING: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C2 : /C1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D2 : /D1> { + } + public abstract [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D2>, /C2> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(RAW_FIR)] annotations container + public? final? [ResolvedTo(SUPER_TYPES)] interface B : , /ResolveMe> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface C2 : /C1> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D1 : /B> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface D2 : /D1> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface ResolveMe : /F> { + } + public? final? [ResolvedTo(SUPER_TYPES)] interface F : /D2>, /C2> { + } + public? final? [ResolvedTo(RAW_FIR)] interface NonLoopedInterface : C2 { + } + +FILE RAW TO BODY: +FILE: [ResolvedTo(IMPORTS)] cyclicHierarchy3.kt + [ResolvedTo(BODY_RESOLVE)] annotations container + public abstract [ResolvedTo(BODY_RESOLVE)] interface B : , /ResolveMe> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface C1 : /B> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface C2 : /C1> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface D1 : /B> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface D2 : /D1> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface ResolveMe : /F> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface F : /D2>, /C2> { + } + public abstract [ResolvedTo(BODY_RESOLVE)] interface NonLoopedInterface : R|C2| { + } diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.kt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.kt new file mode 100644 index 00000000000..290ea6ad73f --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.kt @@ -0,0 +1,4 @@ +open class C : D() { + open class CC +} +open class D : C.CC() \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.txt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.txt new file mode 100644 index 00000000000..aaa67337b4e --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.txt @@ -0,0 +1,321 @@ +RAW_FIR: +FILE: [ResolvedTo(RAW_FIR)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class C : D { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] class CC : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(RAW_FIR)] class D : C.CC { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +IMPORTS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class C : D { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] class CC : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(RAW_FIR)] class D : C.CC { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +COMPILER_REQUIRED_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] class C : D { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] class CC : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(RAW_FIR)] class D : C.CC { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +COMPANION_GENERATION: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(COMPANION_GENERATION)] class C : D { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] class CC : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(RAW_FIR)] class D : C.CC { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +SUPER_TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +STATUS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class C : /D> { + public [ResolvedTo(STATUS)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +EXPECT_ACTUAL_MATCHING: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(EXPECT_ACTUAL_MATCHING)] class C : /D> { + public [ResolvedTo(STATUS)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +ARGUMENTS_OF_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] class C : /D> { + public [ResolvedTo(STATUS)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +CONTRACTS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(CONTRACTS)] class C : /D> { + public [ResolvedTo(STATUS)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +IMPLICIT_TYPES_BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] class C : /D> { + public [ResolvedTo(STATUS)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +ANNOTATIONS_ARGUMENTS_MAPPING: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] class C : /D> { + public [ResolvedTo(STATUS)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(BODY_RESOLVE)] class C : /D> { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=C] constructor(): R|C| { + super() + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public open [ResolvedTo(STATUS)] class D : /C.CC> { + public [ResolvedTo(STATUS)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +FILE RAW TO BODY: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy.kt + [ResolvedTo(BODY_RESOLVE)] annotations container + public open [ResolvedTo(BODY_RESOLVE)] class C : /D> { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=C] constructor(): R|C| { + super() + } + + public open [ResolvedTo(BODY_RESOLVE)] class CC : kotlin/Any> { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=CC] constructor(): R|C.CC| { + super() + } + + } + + } + public open [ResolvedTo(BODY_RESOLVE)] class D : /C.CC> { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=D] constructor(): R|D| { + super() + } + + } diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.kt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.kt new file mode 100644 index 00000000000..5ed10b693d2 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.kt @@ -0,0 +1,4 @@ +open class C : D() { + open class CC +} +open class D : C.CC() \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.txt b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.txt new file mode 100644 index 00000000000..9b5d34005a5 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.txt @@ -0,0 +1,321 @@ +RAW_FIR: +FILE: [ResolvedTo(RAW_FIR)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class C : D { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] class CC : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(RAW_FIR)] class D : C.CC { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +IMPORTS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class C : D { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] class CC : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(RAW_FIR)] class D : C.CC { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +COMPILER_REQUIRED_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class C : D { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] class CC : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] class D : C.CC { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +COMPANION_GENERATION: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class C : D { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(RAW_FIR)] class CC : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(COMPANION_GENERATION)] class D : C.CC { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +SUPER_TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +TYPES: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public? open [ResolvedTo(TYPES)] class D : /C.CC> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +STATUS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public open [ResolvedTo(STATUS)] class D : /C.CC> { + public [ResolvedTo(STATUS)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +EXPECT_ACTUAL_MATCHING: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public open [ResolvedTo(EXPECT_ACTUAL_MATCHING)] class D : /C.CC> { + public [ResolvedTo(STATUS)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +ARGUMENTS_OF_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public open [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] class D : /C.CC> { + public [ResolvedTo(STATUS)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +CONTRACTS: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public open [ResolvedTo(CONTRACTS)] class D : /C.CC> { + public [ResolvedTo(STATUS)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +IMPLICIT_TYPES_BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public open [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] class D : /C.CC> { + public [ResolvedTo(STATUS)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +ANNOTATIONS_ARGUMENTS_MAPPING: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class C : /D> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public? open [ResolvedTo(SUPER_TYPES)] class CC : kotlin/Any> { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public open [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] class D : /C.CC> { + public [ResolvedTo(STATUS)] [ContainingClassKey=D] constructor(): R|D| { + LAZY_super + } + + } + +BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class C : /D> { + public [ResolvedTo(STATUS)] [ContainingClassKey=C] constructor(): R|C| { + LAZY_super + } + + public open [ResolvedTo(STATUS)] class CC : kotlin/Any> { + public [ResolvedTo(STATUS)] [ContainingClassKey=CC] constructor(): R|C.CC| { + LAZY_super + } + + } + + } + public open [ResolvedTo(BODY_RESOLVE)] class D : /C.CC> { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=D] constructor(): R|D| { + super() + } + + } + +FILE RAW TO BODY: +FILE: [ResolvedTo(IMPORTS)] cyclicNestedHierarchy2.kt + [ResolvedTo(BODY_RESOLVE)] annotations container + public open [ResolvedTo(BODY_RESOLVE)] class C : /D> { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=C] constructor(): R|C| { + super() + } + + public open [ResolvedTo(BODY_RESOLVE)] class CC : kotlin/Any> { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=CC] constructor(): R|C.CC| { + super() + } + + } + + } + public open [ResolvedTo(BODY_RESOLVE)] class D : /C.CC> { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=D] constructor(): R|D| { + super() + } + + } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java index 03815de2a28..348f7bd21f3 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java @@ -84,6 +84,36 @@ public class FirOutOfContentRootLazyDeclarationResolveTestGenerated extends Abst runTest("analysis/low-level-api-fir/testdata/lazyResolve/complexLocalHierarchy.kt"); } + @Test + @TestMetadata("cyclicHierarchy.kt") + public void testCyclicHierarchy() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.kt"); + } + + @Test + @TestMetadata("cyclicHierarchy2.kt") + public void testCyclicHierarchy2() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.kt"); + } + + @Test + @TestMetadata("cyclicHierarchy3.kt") + public void testCyclicHierarchy3() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.kt"); + } + + @Test + @TestMetadata("cyclicNestedHierarchy.kt") + public void testCyclicNestedHierarchy() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.kt"); + } + + @Test + @TestMetadata("cyclicNestedHierarchy2.kt") + public void testCyclicNestedHierarchy2() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.kt"); + } + @Test @TestMetadata("dataClassCopy.kt") public void testDataClassCopy() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java index e52d8562e33..e1a0d13991b 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java @@ -84,6 +84,36 @@ public class FirSourceLazyDeclarationResolveTestGenerated extends AbstractFirSou runTest("analysis/low-level-api-fir/testdata/lazyResolve/complexLocalHierarchy.kt"); } + @Test + @TestMetadata("cyclicHierarchy.kt") + public void testCyclicHierarchy() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy.kt"); + } + + @Test + @TestMetadata("cyclicHierarchy2.kt") + public void testCyclicHierarchy2() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy2.kt"); + } + + @Test + @TestMetadata("cyclicHierarchy3.kt") + public void testCyclicHierarchy3() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicHierarchy3.kt"); + } + + @Test + @TestMetadata("cyclicNestedHierarchy.kt") + public void testCyclicNestedHierarchy() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy.kt"); + } + + @Test + @TestMetadata("cyclicNestedHierarchy2.kt") + public void testCyclicNestedHierarchy2() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/cyclicNestedHierarchy2.kt"); + } + @Test @TestMetadata("dataClassCopy.kt") public void testDataClassCopy() throws Exception { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt index 86b92b094e9..6dd50d0bb11 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt @@ -30,11 +30,13 @@ import org.jetbrains.kotlin.fir.declarations.utils.isInner import org.jetbrains.kotlin.fir.declarations.utils.modality import org.jetbrains.kotlin.fir.declarations.utils.visibility import org.jetbrains.kotlin.fir.moduleData +import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.resolve.transformers.resolveSupertypesInTheAir +import org.jetbrains.kotlin.fir.resolve.transformers.FirSupertypeResolverVisitor +import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationSession import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.name.* @@ -113,7 +115,7 @@ class FirJavaElementFinder( val superTypeRefs = when { firClass.superTypeRefs.all { it is FirResolvedTypeRef } -> firClass.superTypeRefs - else -> firClass.resolveSupertypesInTheAir(session) + else -> firClass.resolveSupertypesOnAir(session) } stub.addSupertypesReferencesLists(firClass, superTypeRefs, session) @@ -127,6 +129,13 @@ class FirJavaElementFinder( } +private fun FirRegularClass.resolveSupertypesOnAir(session: FirSession): List { + val visitor = FirSupertypeResolverVisitor(session, SupertypeComputationSession(), ScopeSession()) + return visitor.withFile(session.firProvider.getFirClassifierContainerFile(this.symbol)) { + visitor.resolveSpecificClassLikeSupertypes(this, superTypeRefs) + } +} + private fun FirSession.collectAllDependentSourceSessions(): List { val result = mutableListOf() collectAllDependentSourceSessionsTo(result) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt index 013dc9af4e6..8dec585ee6d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt @@ -50,11 +50,11 @@ class FirSupertypeResolverProcessor(session: FirSession, scopeSession: ScopeSess override val transformer = FirSupertypeResolverTransformer(session, scopeSession) } -open class FirSupertypeResolverTransformer( - final override val session: FirSession, - scopeSession: ScopeSession +class FirSupertypeResolverTransformer( + override val session: FirSession, + scopeSession: ScopeSession, ) : FirAbstractPhaseTransformer(FirResolvePhase.SUPER_TYPES) { - protected val supertypeComputationSession = SupertypeComputationSession() + private val supertypeComputationSession = SupertypeComputationSession() private val supertypeResolverVisitor = FirSupertypeResolverVisitor(session, supertypeComputationSession, scopeSession) private val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession, session, scopeSession) @@ -97,18 +97,18 @@ fun F.runSupertypeResolvePhaseForLocalClass( return this.transform(applySupertypesTransformer, null) } -open class FirApplySupertypesTransformer( +private class FirApplySupertypesTransformer( private val supertypeComputationSession: SupertypeComputationSession, private val session: FirSession, - private val scopeSession: ScopeSession + private val scopeSession: ScopeSession, ) : FirDefaultTransformer() { override fun transformElement(element: E, data: Any?): E { return element } - protected open fun transformDeclarationContent(declaration: FirDeclaration, data: Any?): FirDeclaration { - return declaration.transformChildren(this, null) as FirDeclaration + private fun transformDeclarationContent(declaration: FirDeclaration, data: Any?): FirDeclaration { + return declaration.transformChildren(this, data) as FirDeclaration } override fun transformFile(file: FirFile, data: Any?): FirFile { @@ -200,15 +200,7 @@ private fun createOtherScopesForNestedClassesOrCompanion( // See: prepareScopes() } -fun FirRegularClass.resolveSupertypesInTheAir(session: FirSession): List { - return FirSupertypeResolverVisitor(session, SupertypeComputationSession(), ScopeSession()).run { - withFile(session.firProvider.getFirClassifierContainerFile(this@resolveSupertypesInTheAir.symbol)) { - resolveSpecificClassLikeSupertypes(this@resolveSupertypesInTheAir, superTypeRefs) - } - } -} - -open class FirSupertypeResolverVisitor( +class FirSupertypeResolverVisitor( private val session: FirSession, private val supertypeComputationSession: SupertypeComputationSession, private val scopeSession: ScopeSession, @@ -218,11 +210,14 @@ open class FirSupertypeResolverVisitor( containingDeclarations: List = emptyList(), ) : FirDefaultVisitor() { private val supertypeGenerationExtensions = session.extensionService.supertypeGenerators - private val classDeclarationsStack = ArrayDeque() + + @PrivateForInline + val classDeclarationsStack = ArrayDeque() init { containingDeclarations.forEach { if (it is FirClass) { + @OptIn(PrivateForInline::class) classDeclarationsStack.add(it) } } @@ -280,7 +275,7 @@ open class FirSupertypeResolverVisitor( private fun resolveAllSupertypes( classLikeDeclaration: FirClassLikeDeclaration, supertypeRefs: List, - visited: MutableSet = mutableSetOf() + visited: MutableSet = mutableSetOf(), ) { if (!visited.add(classLikeDeclaration)) return val supertypes: List = @@ -333,8 +328,8 @@ open class FirSupertypeResolverVisitor( private fun resolveSpecificClassLikeSupertypes( classLikeDeclaration: FirClassLikeDeclaration, - resolveSuperTypeRefs: (FirTransformer, ScopeClassDeclaration) -> List - ): List { + resolveSuperTypeRefs: (FirTransformer, ScopeClassDeclaration) -> List, + ): List { when (val status = supertypeComputationSession.getSupertypesComputationStatus(classLikeDeclaration)) { is SupertypeComputationStatus.Computed -> return status.supertypeRefs is SupertypeComputationStatus.Computing -> return listOf( @@ -357,6 +352,7 @@ open class FirSupertypeResolverVisitor( else session.firProvider.getFirClassifierContainerFileIfAny(classLikeDeclaration.symbol) val resolvedTypesRefs = transformer.withFile(newUseSiteFile) { + @OptIn(PrivateForInline::class) resolveSuperTypeRefs( transformer, ScopeClassDeclaration(scopes, classDeclarationsStack, containerDeclaration = classLikeDeclaration), @@ -367,28 +363,38 @@ open class FirSupertypeResolverVisitor( return resolvedTypesRefs } - open fun visitDeclarationContent(declaration: FirDeclaration, data: Any?) { - declaration.acceptChildren(this, null) + private fun visitDeclarationContent(declaration: FirDeclaration, data: Any?) { + declaration.acceptChildren(this, data) + } + + inline fun withClass(firClass: FirClass, body: () -> T) { + @OptIn(PrivateForInline::class) + withClassDeclarationCleanup(classDeclarationsStack, firClass) { + body() + } } override fun visitRegularClass(regularClass: FirRegularClass, data: Any?) { - withClassDeclarationCleanup(classDeclarationsStack, regularClass) { + withClass(regularClass) { resolveSpecificClassLikeSupertypes(regularClass, regularClass.superTypeRefs) visitDeclarationContent(regularClass, null) } } override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Any?) { - withClassDeclarationCleanup(classDeclarationsStack, anonymousObject) { + withClass(anonymousObject) { resolveSpecificClassLikeSupertypes(anonymousObject, anonymousObject.superTypeRefs) visitDeclarationContent(anonymousObject, null) } } + /** + * The function won't call supertypeRefs on classLikeDeclaration directly + */ fun resolveSpecificClassLikeSupertypes( classLikeDeclaration: FirClassLikeDeclaration, - supertypeRefs: List - ): List { + supertypeRefs: List, + ): List { return resolveSpecificClassLikeSupertypes(classLikeDeclaration) { transformer, scopeDeclaration -> if (!classLikeDeclaration.isLocalClassOrAnonymousObject()) { session.lookupTracker?.let { @@ -399,13 +405,8 @@ open class FirSupertypeResolverVisitor( } } } - /* - This list is backed by mutable list and during iterating on it we can resolve supertypes of that class via IDE light classes - as IJ Java resolve may resolve a lot of stuff by light classes - this causes ConcurrentModificationException - So we create a copy of supertypeRefs to avoid it - */ - supertypeRefs.createCopy().mapTo(mutableListOf()) { + + supertypeRefs.mapTo(mutableListOf()) { val superTypeRef = it.transform(transformer, scopeDeclaration) val typeParameterType = superTypeRef.coneTypeSafe() when { @@ -429,13 +430,11 @@ open class FirSupertypeResolverVisitor( } } - private fun List.createCopy(): List = ArrayList(this) - private fun addSupertypesFromExtensions( klass: FirClassLikeDeclaration, supertypeRefs: MutableList, typeResolveTransformer: FirTransformer, - scopeDeclaration: ScopeClassDeclaration + scopeDeclaration: ScopeClassDeclaration, ) { if (supertypeGenerationExtensions.isEmpty()) return val typeResolveService = TypeResolveServiceForPlugins(typeResolveTransformer, scopeDeclaration) @@ -450,7 +449,7 @@ open class FirSupertypeResolverVisitor( private class TypeResolveServiceForPlugins( val typeResolveTransformer: FirTransformer, - val scopeDeclaration: ScopeClassDeclaration + val scopeDeclaration: ScopeClassDeclaration, ) : FirSupertypeGenerationExtension.TypeResolveService() { override fun resolveUserType(type: FirUserTypeRef): FirResolvedTypeRef { return type.transform(typeResolveTransformer, scopeDeclaration) @@ -458,21 +457,24 @@ open class FirSupertypeResolverVisitor( } override fun visitTypeAlias(typeAlias: FirTypeAlias, data: Any?) { + resolveTypeAliasSupertype(typeAlias, typeAlias.expandedTypeRef) + } + + fun resolveTypeAliasSupertype(typeAlias: FirTypeAlias, expandedTypeRef: FirTypeRef): List { // TODO: this if is a temporary hack for built-in types (because we can't load file for them) - if (typeAlias.expandedTypeRef is FirResolvedTypeRef) { - return + if (expandedTypeRef is FirResolvedTypeRef) { + return listOf(expandedTypeRef) } - resolveSpecificClassLikeSupertypes(typeAlias) { transformer, scope -> - val resolvedTypeRef = - transformer.transformTypeRef(typeAlias.expandedTypeRef, scope) as? FirResolvedTypeRef - ?: return@resolveSpecificClassLikeSupertypes listOf( - createErrorTypeRef( - typeAlias.expandedTypeRef, - "Unresolved expanded typeRef for ${typeAlias.symbol.classId}", - DiagnosticKind.UnresolvedExpandedType - ) + return resolveSpecificClassLikeSupertypes(typeAlias) { transformer, scope -> + val resolvedTypeRef = transformer.transformTypeRef(expandedTypeRef, scope) as? FirResolvedTypeRef + ?: return@resolveSpecificClassLikeSupertypes listOf( + createErrorTypeRef( + expandedTypeRef, + "Unresolved expanded typeRef for ${typeAlias.symbol.classId}", + DiagnosticKind.UnresolvedExpandedType ) + ) fun visitNestedTypeAliases(type: TypeArgumentMarker) { if (type is ConeClassLikeType) { @@ -505,11 +507,11 @@ private fun createErrorTypeRef(fir: FirElement, message: String, kind: Diagnosti diagnostic = ConeSimpleDiagnostic(message, kind) } -class SupertypeComputationSession { +open class SupertypeComputationSession { private val fileScopesMap = hashMapOf() private val scopesForNestedClassesMap = hashMapOf() private val scopesForCompanionMap = hashMapOf() - val supertypeStatusMap = linkedMapOf() + private val supertypeStatusMap = linkedMapOf() val supertypesSupplier: SupertypeSupplier = object : SupertypeSupplier() { override fun forClass(firClass: FirClass, useSiteSession: FirSession): List { @@ -558,52 +560,77 @@ class SupertypeComputationSession { private val newClassifiersForBreakingLoops = mutableListOf() - fun breakLoops(session: FirSession) { - val visitedClassLikeDecls = mutableSetOf() - val loopedClassLikeDecls = mutableSetOf() - val path = mutableListOf() - val pathSet = mutableSetOf() + /** + * @return **true** if class is already resolved and can't be a part of loops + */ + protected open fun isAlreadyResolved(classLikeDeclaration: FirClassLikeDeclaration): Boolean = false + + /** + * @param supertypeRefs a collection where at least one element is [FirErrorTypeRef] for looped references + */ + protected open fun reportLoopErrorRefs(classLikeDeclaration: FirClassLikeDeclaration, supertypeRefs: List) { + supertypeStatusMap[classLikeDeclaration] = SupertypeComputationStatus.Computed(supertypeRefs) + } + + protected open fun getResolvedSuperTypeRefsForOutOfSessionDeclaration( + classLikeDeclaration: FirClassLikeDeclaration, + ): List? = when (classLikeDeclaration) { + is FirRegularClass -> classLikeDeclaration.superTypeRefs.filterIsInstance() + is FirTypeAlias -> listOfNotNull(classLikeDeclaration.expandedTypeRef as? FirResolvedTypeRef) + else -> null + } + + /** + * @param declaration declaration to be checked for loops + * @param visited visited declarations during the current loop search + * @param looped declarations inside loop + */ + protected fun breakLoopFor( + declaration: FirClassLikeDeclaration, + session: FirSession, + visited: MutableSet, // always empty for LL FIR + looped: MutableSet, // always empty for LL FIR + pathSet: MutableSet, + path: MutableList, + ) { + require(path.isEmpty()) { "Path should be empty" } + require(pathSet.isEmpty()) { "Path set should be empty" } fun checkIsInLoop( - classLikeDecl: FirClassLikeDeclaration?, + classLikeDeclaration: FirClassLikeDeclaration?, wasSubtypingInvolved: Boolean, wereTypeArgumentsInvolved: Boolean, ) { - if (classLikeDecl == null) return + if (classLikeDeclaration == null || isAlreadyResolved(classLikeDeclaration)) return require(!wasSubtypingInvolved || !wereTypeArgumentsInvolved) { "This must hold by induction, because otherwise such a loop is allowed" } - val supertypeRefs: List - val supertypeComputationStatus = supertypeStatusMap[classLikeDecl] - supertypeRefs = if (supertypeComputationStatus != null) { - require(supertypeComputationStatus is SupertypeComputationStatus.Computed) { - "Expected computed supertypes in breakLoops for ${classLikeDecl.symbol.classId}" + val supertypeStatus = supertypeStatusMap[classLikeDeclaration] + val supertypeRefs: List = if (supertypeStatus != null) { + require(supertypeStatus is SupertypeComputationStatus.Computed) { + "Expected computed supertypes in breakLoops for ${classLikeDeclaration.symbol.classId}" } - supertypeComputationStatus.supertypeRefs + + supertypeStatus.supertypeRefs } else { - when (classLikeDecl) { - is FirRegularClass -> - classLikeDecl.superTypeRefs.filterIsInstance() - is FirTypeAlias -> - (classLikeDecl.expandedTypeRef as? FirResolvedTypeRef)?.let { listOf(it) } ?: listOf() - else -> return - } + getResolvedSuperTypeRefsForOutOfSessionDeclaration(classLikeDeclaration) ?: return } - if (classLikeDecl in visitedClassLikeDecls) { - if (classLikeDecl in pathSet) { - loopedClassLikeDecls.add(classLikeDecl) - loopedClassLikeDecls.addAll(path.takeLastWhile { element -> element != classLikeDecl }) + if (classLikeDeclaration in visited) { + if (classLikeDeclaration in pathSet) { + looped.add(classLikeDeclaration) + looped.addAll(path.takeLastWhile { element -> element != classLikeDeclaration }) } + return } - path.add(classLikeDecl) - pathSet.add(classLikeDecl) - visitedClassLikeDecls.add(classLikeDecl) + path.add(classLikeDeclaration) + pathSet.add(classLikeDeclaration) + visited.add(classLikeDeclaration) - val parentId = classLikeDecl.symbol.classId.relativeClassName.parent() + val parentId = classLikeDeclaration.symbol.classId.relativeClassName.parent() if (!parentId.isRoot) { val parentSymbol = session.symbolProvider.getClassLikeSymbolByClassId(ClassId.fromString(parentId.asString())) if (parentSymbol is FirRegularClassSymbol) { @@ -611,14 +638,14 @@ class SupertypeComputationSession { } } - val isTypeAlias = classLikeDecl is FirTypeAlias + val isTypeAlias = classLikeDeclaration is FirTypeAlias val isSubtypingCurrentlyInvolved = !isTypeAlias // This is an optimization that prevents collecting // loops we don't want to report anyway. if (wereTypeArgumentsInvolved && isSubtypingCurrentlyInvolved) { path.removeAt(path.size - 1) - pathSet.remove(classLikeDecl) + pathSet.remove(classLikeDeclaration) return } @@ -652,11 +679,11 @@ class SupertypeComputationSession { } resultSupertypeRefs.add( - if (classLikeDecl in loopedClassLikeDecls) { + if (classLikeDeclaration in looped) { isErrorInSupertypesFound = true createErrorTypeRef( supertypeRef, - "Loop in supertype: ${classLikeDecl.symbol.classId} -> ${supertypeFir?.symbol?.classId}", + "Loop in supertype: ${classLikeDeclaration.symbol.classId} -> ${supertypeFir?.symbol?.classId}", if (isTypeAlias) DiagnosticKind.RecursiveTypealiasExpansion else DiagnosticKind.LoopInSupertype ) } else { @@ -666,19 +693,34 @@ class SupertypeComputationSession { } if (isErrorInSupertypesFound) { - supertypeStatusMap[classLikeDecl] = SupertypeComputationStatus.Computed(resultSupertypeRefs) + reportLoopErrorRefs(classLikeDeclaration, resultSupertypeRefs) } path.removeAt(path.size - 1) - pathSet.remove(classLikeDecl) + pathSet.remove(classLikeDeclaration) } + checkIsInLoop(declaration, wasSubtypingInvolved = false, wereTypeArgumentsInvolved = false) + require(path.isEmpty()) { "Path should be empty" } + } + + fun breakLoops(session: FirSession) { + val visitedClassLikeDecls = mutableSetOf() + val loopedClassLikeDecls = mutableSetOf() + val path = mutableListOf() + val pathSet = mutableSetOf() + for (classifier in newClassifiersForBreakingLoops) { - checkIsInLoop(classifier, wasSubtypingInvolved = false, wereTypeArgumentsInvolved = false) - require(path.isEmpty()) { - "Path should be empty" - } + breakLoopFor( + declaration = classifier, + session = session, + visited = visitedClassLikeDecls, + looped = loopedClassLikeDecls, + pathSet = pathSet, + path = path, + ) } + newClassifiersForBreakingLoops.clear() } } diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaKotlinCycle.reversed.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaKotlinCycle.reversed.kt deleted file mode 100644 index d2a49a6099f..00000000000 --- a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaKotlinCycle.reversed.kt +++ /dev/null @@ -1,20 +0,0 @@ -// LL_FIR_DIVERGENCE -// The compiler doesn't guarantee exhaustiveness in reporting of inheritance cycles, so the compiler and LL FIR results are equally valid. -// LL_FIR_DIVERGENCE -// FILE: I.kt - -open class I : K() { - fun foo() {} -} - -// FILE: J.java - -class J extends I { - void bar() {} -} - -// FILE: K.kt - -open class K : J() { - fun baz() {} -} diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.reversed.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.ll.kt similarity index 72% rename from compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.reversed.kt rename to compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.ll.kt index 1edd2e30e6d..121536986cc 100644 --- a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.reversed.kt +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.ll.kt @@ -1,3 +1,6 @@ +// LL_FIR_DIVERGENCE +// The compiler doesn't guarantee exhaustiveness in reporting of inheritance cycles, so the compiler and LL FIR results are equally valid. +// LL_FIR_DIVERGENCE // FILE: ExceptionTracker.kt interface ExceptionTracker : LockBasedStorageManager.ExceptionHandlingStrategy {