FIR: Rewrite supertype resolution

This commit is contained in:
Denis Zharkov
2019-11-12 11:07:54 +03:00
parent 9a55f418fa
commit 5e0e78e555
10 changed files with 502 additions and 44 deletions
@@ -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<FirRegularClass>()) {
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<FirTypeRef>,
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<String>()
var superName: String? = null
for (superConeType in firRegularClass.superConeTypes) {
for (superTypeRef in superTypeRefs) {
val superConeType = superTypeRef.coneTypeSafe<ConeClassLikeType>() ?: continue
val supertypeFirClass = superConeType.toFirClass(session) ?: continue
val canonicalString = superConeType.mapToCanonicalString(session)
@@ -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<FirRegularClass>()) {
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<FirTypeRef>,
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<String>()
var superName: String? = null
for (superConeType in firRegularClass.superConeTypes) {
for (superTypeRef in superTypeRefs) {
val superConeType = superTypeRef.coneTypeSafe<ConeClassLikeType>() ?: continue
val supertypeFirClass = superConeType.toFirClass(session) ?: continue
val canonicalString = superConeType.mapToCanonicalString(session)
@@ -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<FirTypeAliasSymbol>()?.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
}
@@ -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<ConeClassLikeType>
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<ConeClassLikeType> {
return mutableListOf<ConeClassLikeType>().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<FirClassifierSymbol<*>>,
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")
}
@@ -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<Nothing?>() {
private val supertypeComputationSession = SupertypeComputationSession()
private val scopeSession = ScopeSession()
private val applySupertypesTransformer = FirApplySupertypesTransformer(supertypeComputationSession)
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
return element.compose()
}
override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult<FirFile> {
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<Nothing?>() {
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
return element.compose()
}
override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult<FirDeclaration> {
return (file.transformChildren(this, null) as FirFile).compose()
}
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult<FirStatement> {
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<FirTypeRef> {
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<FirDeclaration> {
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<FirScope> =
mutableListOf<FirScope>().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<FirRegularClass>().filter { it.isCompanion }
for (companionObject in companionObjects) {
add(nestedClassifierScope(companionObject))
}
add(nestedClassifierScope(regularClass))
}
fun FirRegularClass.resolveSupertypesInTheAir(session: FirSession): List<FirTypeRef> {
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<FirTypeRef>,
visited: MutableSet<FirClassLikeDeclaration<*>> = 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<Nothing?>) -> List<FirTypeRef>
): List<FirTypeRef> {
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<FirTypeRef>
): List<FirTypeRef> {
// 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<ConeTypeParameterType>() != null)
createErrorTypeRef(
superTypeRef,
"Type parameter cannot be a super-type: ${superTypeRef.coneTypeUnsafe<ConeTypeParameterType>().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<FirTypeAliasSymbol>()?.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<FirFile, FirImmutableCompositeScope>()
private val scopesForNestedClassesMap = hashMapOf<FirRegularClass, FirImmutableCompositeScope>()
private val supertypeStatusMap = linkedMapOf<FirClassLikeDeclaration<*>, SupertypeComputationStatus>()
val supertypesSupplier = object : SupertypeSupplier {
override fun forClass(firClass: FirClass<*>): List<ConeClassLikeType> {
if (firClass.resolvePhase > FirResolvePhase.SUPER_TYPES) return firClass.superConeTypes
return (getSupertypesComputationStatus(firClass) as? SupertypeComputationStatus.Computed)?.supertypeRefs?.mapNotNull {
it.coneTypeSafe<ConeClassLikeType>()
}.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<FirTypeRef>) {
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<FirClassLikeDeclaration<*>>()
val inProcess = hashSetOf<FirClassLikeDeclaration<*>>()
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<FirTypeRef>()
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<ConeClassLikeType>() ?: return null
return session.firProvider.getFirClassifierByFqName(type.lookupTag.classId)
}
sealed class SupertypeComputationStatus {
object NotComputed : SupertypeComputationStatus()
object Computing : SupertypeComputationStatus()
class Computed(val supertypeRefs: List<FirTypeRef>) : SupertypeComputationStatus()
}
private typealias ImmutableList<E> = javaslang.collection.List<E>
private class FirImmutableCompositeScope(
private val scopes: ImmutableList<FirScope>
) : FirScope() {
fun childScope(newScope: FirScope?) = newScope?.let { FirImmutableCompositeScope(scopes.push(newScope)) } ?: this
fun childScope(newScopes: Collection<FirScope>) = 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 <T> processComposite(
process: FirScope.(Name, (T) -> ProcessorAction) -> ProcessorAction,
name: Name,
noinline processor: (T) -> ProcessorAction
): ProcessorAction {
val unique = mutableSetOf<T>()
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)
}
}
@@ -16,11 +16,11 @@ fun FirResolvePhase.createTransformerByPhase(): FirTransformer<Nothing?> {
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()
}
}
}
@@ -11,7 +11,15 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.impl.*
fun MutableList<FirScope>.addImportingScopes(file: FirFile, session: FirSession, scopeSession: ScopeSession) {
this += listOf(
this += createImportingScopes(file, session, scopeSession)
}
fun createImportingScopes(
file: FirFile,
session: FirSession,
scopeSession: ScopeSession
): List<FirScope> {
return listOf(
// from low priority to high priority
FirDefaultStarImportingScope(session, scopeSession, priority = DefaultImportPriority.LOW),
FirDefaultStarImportingScope(session, scopeSession, priority = DefaultImportPriority.HIGH),
@@ -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<R|My|>()
}
@@ -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<R|Your|>()
}
@@ -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|
@@ -4,7 +4,7 @@ FILE: K1.kt
super<R|J1|>()
}
public final class Q {
public final class Q : R|class error: Symbol not found, for `Nested`| {
public constructor(): R|K2.Q| {
super<R|class error: Symbol not found, for `Nested`|>()
}