From 5e0e78e555e68dbf299e69a0c848e7117b809b1f Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 12 Nov 2019 11:07:54 +0300 Subject: [PATCH] FIR: Rewrite supertype resolution --- .../kotlin/fir/java/FirJavaElementFinder.kt | 25 +- .../fir/java/FirJavaElementFinder.kt.183 | 25 +- .../kotlin/fir/resolve/ResolveUtils.kt | 7 +- .../kotlin/fir/resolve/SupertypeUtils.kt | 43 +- .../transformers/FirSupertypesResolution.kt | 424 ++++++++++++++++++ .../resolve/transformers/ResolvePhaseUtils.kt | 4 +- .../org/jetbrains/kotlin/fir/scopes/Scopes.kt | 10 +- .../resolve/fakeRecursiveSupertype.txt | 4 +- .../resolve/fakeRecursiveTypealias.txt | 2 +- .../j+k/KJKComplexHierarchyNestedLoop.txt | 2 +- 10 files changed, 502 insertions(+), 44 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt 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 cde40ff91ee..bd47a71cf9a 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 @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.resolve.directExpansionType import org.jetbrains.kotlin.fir.resolve.firProvider import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.resolve.transformers.FirSupertypeResolverTransformer +import org.jetbrains.kotlin.fir.resolve.transformers.resolveSupertypesInTheAir import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.types.* @@ -94,15 +94,12 @@ class FirJavaElementFinder( firClass.typeParameters.map { Pair(it.name.asString(), arrayOf(CommonClassNames.JAVA_LANG_OBJECT)) } ) - if (firClass.supertypesComputationStatus != SupertypesComputationStatus.COMPUTED) { - val firForSuperClassFile = firProvider.getFirClassifierContainerFile(classId) - FirSupertypeResolverTransformer().apply { - initFromFile(firForSuperClassFile) - transformRegularClass(firClass, null) - } + val superTypeRefs = when { + firClass.resolvePhase > FirResolvePhase.SUPER_TYPES -> firClass.superTypeRefs + else -> firClass.resolveSupertypesInTheAir(session) } - stub.addSupertypesReferencesLists(firClass, session) + stub.addSupertypesReferencesLists(firClass, superTypeRefs, session) for (nestedClass in firClass.declarations.filterIsInstance()) { buildStub(nestedClass, stub) @@ -134,9 +131,12 @@ private fun FirRegularClass.packFlags(): Int { return flags } -private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(firRegularClass: FirRegularClass, session: FirSession) { - if (firRegularClass.supertypesComputationStatus == SupertypesComputationStatus.COMPUTING) return - require(firRegularClass.superTypeRefs.all { it is FirResolvedTypeRef }) { +private fun PsiClassStubImpl<*>.addSupertypesReferencesLists( + firRegularClass: FirRegularClass, + superTypeRefs: List, + session: FirSession +) { + require(superTypeRefs.all { it is FirResolvedTypeRef }) { "Supertypes for light class $qualifiedName are being added too early" } @@ -145,7 +145,8 @@ private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(firRegularClass: Fi val interfaceNames = mutableListOf() var superName: String? = null - for (superConeType in firRegularClass.superConeTypes) { + for (superTypeRef in superTypeRefs) { + val superConeType = superTypeRef.coneTypeSafe() ?: continue val supertypeFirClass = superConeType.toFirClass(session) ?: continue val canonicalString = superConeType.mapToCanonicalString(session) diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt.183 b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt.183 index 1cd7ff66161..2d2b30db068 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt.183 +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaElementFinder.kt.183 @@ -24,11 +24,10 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.psi -import org.jetbrains.kotlin.fir.resolve.FirProvider import org.jetbrains.kotlin.fir.resolve.directExpansionType import org.jetbrains.kotlin.fir.resolve.firProvider import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.resolve.transformers.FirSupertypeResolverTransformer +import org.jetbrains.kotlin.fir.resolve.transformers.resolveSupertypesInTheAir import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.types.* @@ -95,15 +94,12 @@ class FirJavaElementFinder( firClass.typeParameters.map { Pair(it.name.asString(), arrayOf(CommonClassNames.JAVA_LANG_OBJECT)) } ) - if (firClass.supertypesComputationStatus != SupertypesComputationStatus.COMPUTED) { - val firForSuperClassFile = firProvider.getFirClassifierContainerFile(classId) - FirSupertypeResolverTransformer().apply { - initFromFile(firForSuperClassFile) - transformRegularClass(firClass, null) - } + val superTypeRefs = when { + firClass.resolvePhase > FirResolvePhase.SUPER_TYPES -> firClass.superTypeRefs + else -> firClass.resolveSupertypesInTheAir(session) } - stub.addSupertypesReferencesLists(firClass, session) + stub.addSupertypesReferencesLists(firClass, superTypeRefs, session) for (nestedClass in firClass.declarations.filterIsInstance()) { buildStub(nestedClass, stub) @@ -135,9 +131,13 @@ private fun FirRegularClass.packFlags(): Int { return flags } -private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(firRegularClass: FirRegularClass, session: FirSession) { +private fun PsiClassStubImpl<*>.addSupertypesReferencesLists( + firRegularClass: FirRegularClass, + superTypeRefs: List, + session: FirSession +) { if (firRegularClass.supertypesComputationStatus == SupertypesComputationStatus.COMPUTING) return - require(firRegularClass.superTypeRefs.all { it is FirResolvedTypeRef }) { + require(superTypeRefs.all { it is FirResolvedTypeRef }) { "Supertypes for light class $qualifiedName are being added too early" } @@ -146,7 +146,8 @@ private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(firRegularClass: Fi val interfaceNames = mutableListOf() var superName: String? = null - for (superConeType in firRegularClass.superConeTypes) { + for (superTypeRef in superTypeRefs) { + val superConeType = superTypeRef.coneTypeSafe() ?: continue val supertypeFirClass = superConeType.toFirClass(session) ?: continue val canonicalString = superConeType.mapToCanonicalString(session) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index ced8df9b17f..8313d73c9c4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -57,12 +57,15 @@ fun ConeClassLikeLookupTag.toSymbol(useSiteSession: FirSession): FirClassLikeSym return firSymbolProvider.getSymbolByLookupTag(this) } -fun ConeAbbreviatedType.directExpansionType(useSiteSession: FirSession): ConeClassLikeType? { +fun ConeAbbreviatedType.directExpansionType( + useSiteSession: FirSession, + expandedConeType: (FirTypeAlias) -> ConeClassLikeType? = FirTypeAlias::expandedConeType +): ConeClassLikeType? { val typeAlias = abbreviationLookupTag .toSymbol(useSiteSession) ?.safeAs()?.fir ?: return null - val resultType = typeAlias.expandedConeType ?: return null + val resultType = expandedConeType(typeAlias) ?: return null if (resultType.typeArguments.isEmpty()) return resultType return mapTypeAliasArguments(typeAlias, this, resultType) as? ConeClassLikeType } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt index b72f8f7770d..513b82eb4a1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/SupertypeUtils.kt @@ -13,14 +13,25 @@ import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.* +interface SupertypeSupplier { + fun forClass(firClass: FirClass<*>): List + fun expansionForTypeAlias(typeAlias: FirTypeAlias): ConeClassLikeType? + + object Default : SupertypeSupplier { + override fun forClass(firClass: FirClass<*>) = firClass.superConeTypes + override fun expansionForTypeAlias(typeAlias: FirTypeAlias) = typeAlias.expandedConeType + } +} + fun lookupSuperTypes( klass: FirClass<*>, lookupInterfaces: Boolean, deep: Boolean, - useSiteSession: FirSession + useSiteSession: FirSession, + supertypeSupplier: SupertypeSupplier = SupertypeSupplier.Default ): List { return mutableListOf().also { - klass.symbol.collectSuperTypes(it, mutableSetOf(), deep, lookupInterfaces, useSiteSession) + klass.symbol.collectSuperTypes(it, mutableSetOf(), deep, lookupInterfaces, useSiteSession, supertypeSupplier) } } @@ -109,9 +120,15 @@ fun ConeClassLikeType.wrapSubstitutionScopeIfNeed( } } -private tailrec fun ConeClassLikeType.computePartialExpansion(useSiteSession: FirSession): ConeClassLikeType? { +private tailrec fun ConeClassLikeType.computePartialExpansion( + useSiteSession: FirSession, + supertypeSupplier: SupertypeSupplier +): ConeClassLikeType? { return when (this) { - is ConeAbbreviatedType -> directExpansionType(useSiteSession)?.computePartialExpansion(useSiteSession) + is ConeAbbreviatedType -> + directExpansionType(useSiteSession) { + supertypeSupplier.expansionForTypeAlias(it) + }?.computePartialExpansion(useSiteSession, supertypeSupplier) else -> this } } @@ -121,14 +138,15 @@ private fun FirClassifierSymbol<*>.collectSuperTypes( visitedSymbols: MutableSet>, deep: Boolean, lookupInterfaces: Boolean, - useSiteSession: FirSession + useSiteSession: FirSession, + supertypeSupplier: SupertypeSupplier ) { if (!visitedSymbols.add(this)) return when (this) { - is FirClassSymbol -> { + is FirClassSymbol<*> -> { val superClassTypes = - superConeTypes.mapNotNull { - it.computePartialExpansion(useSiteSession) + supertypeSupplier.forClass(fir).mapNotNull { + it.computePartialExpansion(useSiteSession, supertypeSupplier) .takeIf { type -> lookupInterfaces || type.isClassBasedType(useSiteSession) } } list += superClassTypes @@ -140,14 +158,17 @@ private fun FirClassifierSymbol<*>.collectSuperTypes( visitedSymbols, deep, lookupInterfaces, - useSiteSession + useSiteSession, + supertypeSupplier ) } } } is FirTypeAliasSymbol -> { - val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return - expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, visitedSymbols, deep, lookupInterfaces, useSiteSession) + val expansion = + supertypeSupplier.expansionForTypeAlias(fir)?.computePartialExpansion(useSiteSession, supertypeSupplier) ?: return + expansion.lookupTag.toSymbol(useSiteSession) + ?.collectSuperTypes(list, visitedSymbols, deep, lookupInterfaces, useSiteSession, supertypeSupplier) } else -> error("?!id:1") } 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 new file mode 100644 index 00000000000..77e76494c78 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt @@ -0,0 +1,424 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.transformers + +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic +import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.scopes.FirScope +import org.jetbrains.kotlin.fir.scopes.ProcessorAction +import org.jetbrains.kotlin.fir.scopes.createImportingScopes +import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope +import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol +import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl +import org.jetbrains.kotlin.fir.visitors.* +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addIfNotNull +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +class FirSupertypeResolverTransformerAdapter : FirTransformer() { + private val supertypeComputationSession = SupertypeComputationSession() + private val scopeSession = ScopeSession() + private val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession) + + override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { + return element.compose() + } + + override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult { + val supertypeResolverVisitor = FirSupertypeResolverVisitor(file.session, supertypeComputationSession, scopeSession) + file.accept(supertypeResolverVisitor) + supertypeComputationSession.breakLoops(file.session) + return file.transform(applySupertypesTransformer, null) + } +} + +private class FirApplySupertypesTransformer( + private val supertypeComputationSession: SupertypeComputationSession +) : FirDefaultTransformer() { + override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { + return element.compose() + } + + override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult { + return (file.transformChildren(this, null) as FirFile).compose() + } + + override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult { + if (regularClass.superTypeRefs.any { it !is FirResolvedTypeRef }) { + val supertypeRefs = getResolvedSupertypeRefs(regularClass) + + // TODO: Replace with an immutable version or transformer + regularClass.replaceSuperTypeRefs(supertypeRefs) + regularClass.replaceResolvePhase(FirResolvePhase.SUPER_TYPES) + } + + return (regularClass.transformChildren(this, null) as FirRegularClass).compose() + } + + private fun getResolvedSupertypeRefs(classLikeDeclaration: FirClassLikeDeclaration<*>): List { + val status = supertypeComputationSession.getSupertypesComputationStatus(classLikeDeclaration) + require(status is SupertypeComputationStatus.Computed) { + "Unexpected status at FirApplySupertypesTransformer: $status for ${classLikeDeclaration.symbol.classId}" + } + return status.supertypeRefs + } + + override fun transformTypeAlias(typeAlias: FirTypeAlias, data: Nothing?): CompositeTransformResult { + if (typeAlias.expandedTypeRef is FirResolvedTypeRef) return typeAlias.compose() + val supertypeRefs = getResolvedSupertypeRefs(typeAlias) + + assert(supertypeRefs.size == 1) { + "Expected single supertypeRefs, but found ${supertypeRefs.size} in ${typeAlias.symbol.classId}" + } + + // TODO: Replace with an immutable version or transformer + typeAlias.replaceExpandedTypeRef(supertypeRefs[0]) + typeAlias.replaceResolvePhase(FirResolvePhase.SUPER_TYPES) + + return typeAlias.compose() + } +} + +private fun FirClassLikeDeclaration<*>.typeParametersScope(): FirScope? { + if (this !is FirMemberDeclaration || typeParameters.isEmpty()) return null + return FirMemberTypeParameterScope(this) +} + +private fun createScopesForNestedClasses( + regularClass: FirRegularClass, + session: FirSession, + supertypeComputationSession: SupertypeComputationSession +): Collection = + mutableListOf().apply { + lookupSuperTypes( + regularClass, + lookupInterfaces = false, deep = true, useSiteSession = session, + supertypeSupplier = supertypeComputationSession.supertypesSupplier + ).asReversed().mapTo(this) { + nestedClassifierScope(it.lookupTag.classId, session) + } + addIfNotNull(regularClass.typeParametersScope()) + val companionObjects = regularClass.declarations.filterIsInstance().filter { it.isCompanion } + for (companionObject in companionObjects) { + add(nestedClassifierScope(companionObject)) + } + add(nestedClassifierScope(regularClass)) + } + +fun FirRegularClass.resolveSupertypesInTheAir(session: FirSession): List { + return FirSupertypeResolverVisitor(session, SupertypeComputationSession(), ScopeSession()) + .resolveSpecificClassLikeSupertypes(this, superTypeRefs) +} + +private class FirSupertypeResolverVisitor( + private val session: FirSession, + private val supertypeComputationSession: SupertypeComputationSession, + private val scopeSession: ScopeSession +) : FirDefaultVisitorVoid() { + override fun visitElement(element: FirElement) {} + + private fun prepareFileScope(file: FirFile): FirImmutableCompositeScope { + return supertypeComputationSession.getOrPutFileScope(file) { + FirImmutableCompositeScope(ImmutableList.ofAll(createImportingScopes(file, session, scopeSession).asReversed())) + } + } + + private fun prepareScopeForNestedClasses(regularClass: FirRegularClass): FirImmutableCompositeScope { + return supertypeComputationSession.getOrPutScopeForNestedClasses(regularClass) { + val scope = prepareScope(regularClass) + + resolveAllSupertypes(regularClass, regularClass.superTypeRefs) + + scope.childScope(createScopesForNestedClasses(regularClass, session, supertypeComputationSession)) + } + } + + private fun resolveAllSupertypes( + classLikeDeclaration: FirClassLikeDeclaration<*>, + supertypeRefs: List, + visited: MutableSet> = mutableSetOf() + ) { + if (!visited.add(classLikeDeclaration)) return + val supertypes = + resolveSpecificClassLikeSupertypes(classLikeDeclaration, supertypeRefs) + .mapNotNull { (it as? FirResolvedTypeRef)?.type } + + for (supertype in supertypes) { + if (supertype !is ConeClassLikeType) continue + val fir = session.firProvider.getFirClassifierByFqName(supertype.lookupTag.classId) ?: continue + resolveAllSupertypes(fir, fir.supertypeRefs(), visited) + } + } + + private fun FirClassLikeDeclaration<*>.supertypeRefs() = when (this) { + is FirRegularClass -> superTypeRefs + is FirTypeAlias -> listOf(expandedTypeRef) + else -> emptyList() + } + + private fun prepareScope(classLikeDeclaration: FirClassLikeDeclaration<*>): FirImmutableCompositeScope { + val classId = classLikeDeclaration.symbol.classId + val outerClassFir = classId.outerClassId?.let(session.firProvider::getFirClassifierByFqName) as? FirRegularClass + + val result = if (outerClassFir == null) { + prepareFileScope(session.firProvider.getFirClassifierContainerFile(classId)) + } else { + prepareScopeForNestedClasses(outerClassFir) + } + + return result.childScope(classLikeDeclaration.typeParametersScope()) + } + + private fun resolveSpecificClassLikeSupertypes( + classLikeDeclaration: FirClassLikeDeclaration<*>, + resolveSuperTypeRefs: (FirTransformer) -> List + ): List { + when (val status = supertypeComputationSession.getSupertypesComputationStatus(classLikeDeclaration)) { + is SupertypeComputationStatus.Computed -> return status.supertypeRefs + is SupertypeComputationStatus.Computing -> return listOf( + createErrorTypeRef(classLikeDeclaration, "Loop in supertype definition for ${classLikeDeclaration.symbol.classId}") + ) + } + + supertypeComputationSession.startComputingSupertypes(classLikeDeclaration) + val scope = prepareScope(classLikeDeclaration) + + val transformer = FirSpecificTypeResolverTransformer(scope, session) + val resolvedTypesRefs = resolveSuperTypeRefs(transformer) + + supertypeComputationSession.storeSupertypes(classLikeDeclaration, resolvedTypesRefs) + return resolvedTypesRefs + } + + override fun visitRegularClass(regularClass: FirRegularClass) { + resolveSpecificClassLikeSupertypes(regularClass, regularClass.superTypeRefs) + regularClass.acceptChildren(this) + } + + fun resolveSpecificClassLikeSupertypes( + classLikeDeclaration: FirClassLikeDeclaration<*>, + supertypeRefs: List + ): List { + // TODO: this if is a temporary hack for built-in types (because we can't load file for them) + if (supertypeRefs.all { it is FirResolvedTypeRef }) { + return supertypeRefs + } + + return resolveSpecificClassLikeSupertypes(classLikeDeclaration) { transformer -> + supertypeRefs.map { + val superTypeRef = transformer.transformTypeRef(it, null).single + + if (superTypeRef.coneTypeSafe() != null) + createErrorTypeRef( + superTypeRef, + "Type parameter cannot be a super-type: ${superTypeRef.coneTypeUnsafe().render()}" + ) + else + superTypeRef + } + } + } + + override fun visitTypeAlias(typeAlias: FirTypeAlias) { + // 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 + } + + resolveSpecificClassLikeSupertypes(typeAlias) { transformer -> + val resolvedTypeRef = + transformer.transformTypeRef(typeAlias.expandedTypeRef, null).single as? FirResolvedTypeRef + ?: return@resolveSpecificClassLikeSupertypes listOf( + createErrorTypeRef( + typeAlias.expandedTypeRef, + "Unresolved expanded typeRef for ${typeAlias.symbol.classId}" + ) + ) + + val type = resolvedTypeRef.type + if (type is ConeAbbreviatedType) { + val expansionTypeAlias = type.abbreviationLookupTag.toSymbol(session)?.safeAs()?.fir + if (expansionTypeAlias != null) { + visitTypeAlias(expansionTypeAlias) + } + } + + listOf(resolvedTypeRef) + } + } + + override fun visitFile(file: FirFile) { + file.acceptChildren(this) + } +} + +private fun createErrorTypeRef(fir: FirElement, message: String) = FirErrorTypeRefImpl(fir.source, FirSimpleDiagnostic(message)) + +private class SupertypeComputationSession { + private val fileScopesMap = hashMapOf() + private val scopesForNestedClassesMap = hashMapOf() + private val supertypeStatusMap = linkedMapOf, SupertypeComputationStatus>() + + val supertypesSupplier = object : SupertypeSupplier { + override fun forClass(firClass: FirClass<*>): List { + if (firClass.resolvePhase > FirResolvePhase.SUPER_TYPES) return firClass.superConeTypes + return (getSupertypesComputationStatus(firClass) as? SupertypeComputationStatus.Computed)?.supertypeRefs?.mapNotNull { + it.coneTypeSafe() + }.orEmpty() + } + + override fun expansionForTypeAlias(typeAlias: FirTypeAlias): ConeClassLikeType? { + if (typeAlias.resolvePhase > FirResolvePhase.SUPER_TYPES) return typeAlias.expandedConeType + return (getSupertypesComputationStatus(typeAlias) as? SupertypeComputationStatus.Computed) + ?.supertypeRefs + ?.getOrNull(0)?.coneTypeSafe() + } + } + + fun getSupertypesComputationStatus(classLikeDeclaration: FirClassLikeDeclaration<*>): SupertypeComputationStatus = + supertypeStatusMap[classLikeDeclaration] ?: SupertypeComputationStatus.NotComputed + + fun getOrPutFileScope(file: FirFile, scope: () -> FirImmutableCompositeScope): FirImmutableCompositeScope = + fileScopesMap.getOrPut(file) { scope() } + + fun getOrPutScopeForNestedClasses(regularClass: FirRegularClass, scope: () -> FirImmutableCompositeScope): FirImmutableCompositeScope = + scopesForNestedClassesMap.getOrPut(regularClass) { scope() } + + fun startComputingSupertypes(classLikeDeclaration: FirClassLikeDeclaration<*>) { + require(supertypeStatusMap[classLikeDeclaration] == null) { + "Unexpected in startComputingSupertypes supertype status for $classLikeDeclaration: ${supertypeStatusMap[classLikeDeclaration]}" + } + + supertypeStatusMap[classLikeDeclaration] = SupertypeComputationStatus.Computing + } + + fun storeSupertypes(classLikeDeclaration: FirClassLikeDeclaration<*>, resolvedTypesRefs: List) { + require(supertypeStatusMap[classLikeDeclaration] is SupertypeComputationStatus.Computing) { + "Unexpected in storeSupertypes supertype status for $classLikeDeclaration: ${supertypeStatusMap[classLikeDeclaration]}" + } + + supertypeStatusMap[classLikeDeclaration] = SupertypeComputationStatus.Computed(resolvedTypesRefs) + } + + fun breakLoops(session: FirSession) { + val visited = hashSetOf>() + val inProcess = hashSetOf>() + + fun dfs(classLikeDeclaration: FirClassLikeDeclaration<*>) { + val supertypeComputationStatus = supertypeStatusMap[classLikeDeclaration] ?: return + if (classLikeDeclaration in visited) return + if (classLikeDeclaration in inProcess) return + + inProcess.add(classLikeDeclaration) + + require(supertypeComputationStatus is SupertypeComputationStatus.Computed) { + "Expected computed supertypes in breakLoops for ${classLikeDeclaration.symbol.classId}" + } + + val typeRefs = supertypeComputationStatus.supertypeRefs + val resultingTypeRefs = mutableListOf() + var wereChanges = false + + for (typeRef in typeRefs) { + val fir = typeRef.firClassLike(session) + fir?.let(::dfs) + resultingTypeRefs.add( + if (fir in inProcess) { + wereChanges = true + createErrorTypeRef( + typeRef, + "Loop in supertype: ${classLikeDeclaration.symbol.classId} -> ${fir?.symbol?.classId}" + ) + } else + typeRef + ) + } + + if (wereChanges) { + supertypeStatusMap[classLikeDeclaration] = SupertypeComputationStatus.Computed(resultingTypeRefs) + } + + inProcess.remove(classLikeDeclaration) + visited.add(classLikeDeclaration) + } + + for (classifier in supertypeStatusMap.keys) { + dfs(classifier) + } + } +} + +fun FirTypeRef.firClassLike(session: FirSession): FirClassLikeDeclaration<*>? { + val type = coneTypeSafe() ?: return null + return session.firProvider.getFirClassifierByFqName(type.lookupTag.classId) +} + +sealed class SupertypeComputationStatus { + object NotComputed : SupertypeComputationStatus() + object Computing : SupertypeComputationStatus() + + class Computed(val supertypeRefs: List) : SupertypeComputationStatus() +} + +private typealias ImmutableList = javaslang.collection.List + +private class FirImmutableCompositeScope( + private val scopes: ImmutableList +) : FirScope() { + + fun childScope(newScope: FirScope?) = newScope?.let { FirImmutableCompositeScope(scopes.push(newScope)) } ?: this + fun childScope(newScopes: Collection) = FirImmutableCompositeScope(scopes.pushAll(newScopes)) + + override fun processClassifiersByName( + name: Name, + processor: (FirClassifierSymbol<*>) -> ProcessorAction + ): ProcessorAction { + for (scope in scopes) { + if (!scope.processClassifiersByName(name, processor)) { + return ProcessorAction.STOP + } + } + return ProcessorAction.NEXT + } + + private inline fun processComposite( + process: FirScope.(Name, (T) -> ProcessorAction) -> ProcessorAction, + name: Name, + noinline processor: (T) -> ProcessorAction + ): ProcessorAction { + val unique = mutableSetOf() + for (scope in scopes) { + if (!scope.process(name) { + if (unique.add(it)) { + processor(it) + } else { + ProcessorAction.NEXT + } + } + ) { + return ProcessorAction.STOP + } + } + return ProcessorAction.NEXT + } + + override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> ProcessorAction): ProcessorAction { + return processComposite(FirScope::processFunctionsByName, name, processor) + } + + override fun processPropertiesByName(name: Name, processor: (FirCallableSymbol<*>) -> ProcessorAction): ProcessorAction { + return processComposite(FirScope::processPropertiesByName, name, processor) + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt index 0a4657854a9..1203272f4b7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt @@ -16,11 +16,11 @@ fun FirResolvePhase.createTransformerByPhase(): FirTransformer { return when (this) { RAW_FIR -> throw AssertionError("Raw FIR building phase does not have a transformer") IMPORTS -> FirImportResolveTransformer() - SUPER_TYPES -> FirSupertypeResolverTransformer() + SUPER_TYPES -> FirSupertypeResolverTransformerAdapter() SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsTransformer() TYPES -> FirTypeResolveTransformer() STATUS -> FirStatusResolveTransformer() IMPLICIT_TYPES_BODY_RESOLVE -> FirImplicitTypeBodyResolveTransformerAdapter() BODY_RESOLVE -> FirBodyResolveTransformerAdapter() } -} \ No newline at end of file +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt index ac1e8ab0863..15b409b438c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/scopes/Scopes.kt @@ -11,7 +11,15 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.scopes.impl.* fun MutableList.addImportingScopes(file: FirFile, session: FirSession, scopeSession: ScopeSession) { - this += listOf( + this += createImportingScopes(file, session, scopeSession) +} + +fun createImportingScopes( + file: FirFile, + session: FirSession, + scopeSession: ScopeSession +): List { + return listOf( // from low priority to high priority FirDefaultStarImportingScope(session, scopeSession, priority = DefaultImportPriority.LOW), FirDefaultStarImportingScope(session, scopeSession, priority = DefaultImportPriority.HIGH), diff --git a/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.txt b/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.txt index 01562ddc946..0099c84f488 100644 --- a/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.txt +++ b/compiler/fir/resolve/testData/resolve/fakeRecursiveSupertype.txt @@ -1,5 +1,5 @@ FILE: fakeRecursiveSupertype.kt - public final class My : R|class error: Recursion detected: R|My|| { + public final class My : R|class error: Loop in supertype: /My -> /My| { public constructor(): R|My| { super() } @@ -11,7 +11,7 @@ FILE: fakeRecursiveSupertype.kt } } - public final class His : R|class error: Recursion detected: R|Your|| { + public final class His : R|class error: Loop in supertype: /His -> /Your| { public constructor(): R|His| { super() } diff --git a/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.txt b/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.txt index 669257af820..c9397354d7b 100644 --- a/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.txt +++ b/compiler/fir/resolve/testData/resolve/fakeRecursiveTypealias.txt @@ -1,3 +1,3 @@ FILE: fakeRecursiveTypealias.kt public final typealias My = R|class error: Symbol not found, for `incorrect.directory.My`| - public final typealias Your = R|class error: Recursion detected: R|Your|| + public final typealias Your = R|class error: Loop in supertype: /Your -> /Your| diff --git a/compiler/fir/resolve/testData/resolve/stdlib/j+k/KJKComplexHierarchyNestedLoop.txt b/compiler/fir/resolve/testData/resolve/stdlib/j+k/KJKComplexHierarchyNestedLoop.txt index 98e5964a80d..fa525279f3c 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/j+k/KJKComplexHierarchyNestedLoop.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/j+k/KJKComplexHierarchyNestedLoop.txt @@ -4,7 +4,7 @@ FILE: K1.kt super() } - public final class Q { + public final class Q : R|class error: Symbol not found, for `Nested`| { public constructor(): R|K2.Q| { super() }