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.directExpansionType
import org.jetbrains.kotlin.fir.resolve.firProvider import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol 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.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
@@ -94,15 +94,12 @@ class FirJavaElementFinder(
firClass.typeParameters.map { Pair(it.name.asString(), arrayOf(CommonClassNames.JAVA_LANG_OBJECT)) } firClass.typeParameters.map { Pair(it.name.asString(), arrayOf(CommonClassNames.JAVA_LANG_OBJECT)) }
) )
if (firClass.supertypesComputationStatus != SupertypesComputationStatus.COMPUTED) { val superTypeRefs = when {
val firForSuperClassFile = firProvider.getFirClassifierContainerFile(classId) firClass.resolvePhase > FirResolvePhase.SUPER_TYPES -> firClass.superTypeRefs
FirSupertypeResolverTransformer().apply { else -> firClass.resolveSupertypesInTheAir(session)
initFromFile(firForSuperClassFile)
transformRegularClass(firClass, null)
}
} }
stub.addSupertypesReferencesLists(firClass, session) stub.addSupertypesReferencesLists(firClass, superTypeRefs, session)
for (nestedClass in firClass.declarations.filterIsInstance<FirRegularClass>()) { for (nestedClass in firClass.declarations.filterIsInstance<FirRegularClass>()) {
buildStub(nestedClass, stub) buildStub(nestedClass, stub)
@@ -134,9 +131,12 @@ private fun FirRegularClass.packFlags(): Int {
return flags return flags
} }
private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(firRegularClass: FirRegularClass, session: FirSession) { private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(
if (firRegularClass.supertypesComputationStatus == SupertypesComputationStatus.COMPUTING) return firRegularClass: FirRegularClass,
require(firRegularClass.superTypeRefs.all { it is FirResolvedTypeRef }) { superTypeRefs: List<FirTypeRef>,
session: FirSession
) {
require(superTypeRefs.all { it is FirResolvedTypeRef }) {
"Supertypes for light class $qualifiedName are being added too early" "Supertypes for light class $qualifiedName are being added too early"
} }
@@ -145,7 +145,8 @@ private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(firRegularClass: Fi
val interfaceNames = mutableListOf<String>() val interfaceNames = mutableListOf<String>()
var superName: String? = null 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 supertypeFirClass = superConeType.toFirClass(session) ?: continue
val canonicalString = superConeType.mapToCanonicalString(session) 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.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.psi 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.directExpansionType
import org.jetbrains.kotlin.fir.resolve.firProvider import org.jetbrains.kotlin.fir.resolve.firProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol 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.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
@@ -95,15 +94,12 @@ class FirJavaElementFinder(
firClass.typeParameters.map { Pair(it.name.asString(), arrayOf(CommonClassNames.JAVA_LANG_OBJECT)) } firClass.typeParameters.map { Pair(it.name.asString(), arrayOf(CommonClassNames.JAVA_LANG_OBJECT)) }
) )
if (firClass.supertypesComputationStatus != SupertypesComputationStatus.COMPUTED) { val superTypeRefs = when {
val firForSuperClassFile = firProvider.getFirClassifierContainerFile(classId) firClass.resolvePhase > FirResolvePhase.SUPER_TYPES -> firClass.superTypeRefs
FirSupertypeResolverTransformer().apply { else -> firClass.resolveSupertypesInTheAir(session)
initFromFile(firForSuperClassFile)
transformRegularClass(firClass, null)
}
} }
stub.addSupertypesReferencesLists(firClass, session) stub.addSupertypesReferencesLists(firClass, superTypeRefs, session)
for (nestedClass in firClass.declarations.filterIsInstance<FirRegularClass>()) { for (nestedClass in firClass.declarations.filterIsInstance<FirRegularClass>()) {
buildStub(nestedClass, stub) buildStub(nestedClass, stub)
@@ -135,9 +131,13 @@ private fun FirRegularClass.packFlags(): Int {
return flags 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 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" "Supertypes for light class $qualifiedName are being added too early"
} }
@@ -146,7 +146,8 @@ private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(firRegularClass: Fi
val interfaceNames = mutableListOf<String>() val interfaceNames = mutableListOf<String>()
var superName: String? = null 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 supertypeFirClass = superConeType.toFirClass(session) ?: continue
val canonicalString = superConeType.mapToCanonicalString(session) val canonicalString = superConeType.mapToCanonicalString(session)
@@ -57,12 +57,15 @@ fun ConeClassLikeLookupTag.toSymbol(useSiteSession: FirSession): FirClassLikeSym
return firSymbolProvider.getSymbolByLookupTag(this) return firSymbolProvider.getSymbolByLookupTag(this)
} }
fun ConeAbbreviatedType.directExpansionType(useSiteSession: FirSession): ConeClassLikeType? { fun ConeAbbreviatedType.directExpansionType(
useSiteSession: FirSession,
expandedConeType: (FirTypeAlias) -> ConeClassLikeType? = FirTypeAlias::expandedConeType
): ConeClassLikeType? {
val typeAlias = abbreviationLookupTag val typeAlias = abbreviationLookupTag
.toSymbol(useSiteSession) .toSymbol(useSiteSession)
?.safeAs<FirTypeAliasSymbol>()?.fir ?: return null ?.safeAs<FirTypeAliasSymbol>()?.fir ?: return null
val resultType = typeAlias.expandedConeType ?: return null val resultType = expandedConeType(typeAlias) ?: return null
if (resultType.typeArguments.isEmpty()) return resultType if (resultType.typeArguments.isEmpty()) return resultType
return mapTypeAliasArguments(typeAlias, this, resultType) as? ConeClassLikeType 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.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* 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( fun lookupSuperTypes(
klass: FirClass<*>, klass: FirClass<*>,
lookupInterfaces: Boolean, lookupInterfaces: Boolean,
deep: Boolean, deep: Boolean,
useSiteSession: FirSession useSiteSession: FirSession,
supertypeSupplier: SupertypeSupplier = SupertypeSupplier.Default
): List<ConeClassLikeType> { ): List<ConeClassLikeType> {
return mutableListOf<ConeClassLikeType>().also { 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) { return when (this) {
is ConeAbbreviatedType -> directExpansionType(useSiteSession)?.computePartialExpansion(useSiteSession) is ConeAbbreviatedType ->
directExpansionType(useSiteSession) {
supertypeSupplier.expansionForTypeAlias(it)
}?.computePartialExpansion(useSiteSession, supertypeSupplier)
else -> this else -> this
} }
} }
@@ -121,14 +138,15 @@ private fun FirClassifierSymbol<*>.collectSuperTypes(
visitedSymbols: MutableSet<FirClassifierSymbol<*>>, visitedSymbols: MutableSet<FirClassifierSymbol<*>>,
deep: Boolean, deep: Boolean,
lookupInterfaces: Boolean, lookupInterfaces: Boolean,
useSiteSession: FirSession useSiteSession: FirSession,
supertypeSupplier: SupertypeSupplier
) { ) {
if (!visitedSymbols.add(this)) return if (!visitedSymbols.add(this)) return
when (this) { when (this) {
is FirClassSymbol -> { is FirClassSymbol<*> -> {
val superClassTypes = val superClassTypes =
superConeTypes.mapNotNull { supertypeSupplier.forClass(fir).mapNotNull {
it.computePartialExpansion(useSiteSession) it.computePartialExpansion(useSiteSession, supertypeSupplier)
.takeIf { type -> lookupInterfaces || type.isClassBasedType(useSiteSession) } .takeIf { type -> lookupInterfaces || type.isClassBasedType(useSiteSession) }
} }
list += superClassTypes list += superClassTypes
@@ -140,14 +158,17 @@ private fun FirClassifierSymbol<*>.collectSuperTypes(
visitedSymbols, visitedSymbols,
deep, deep,
lookupInterfaces, lookupInterfaces,
useSiteSession useSiteSession,
supertypeSupplier
) )
} }
} }
} }
is FirTypeAliasSymbol -> { is FirTypeAliasSymbol -> {
val expansion = fir.expandedConeType?.computePartialExpansion(useSiteSession) ?: return val expansion =
expansion.lookupTag.toSymbol(useSiteSession)?.collectSuperTypes(list, visitedSymbols, deep, lookupInterfaces, useSiteSession) supertypeSupplier.expansionForTypeAlias(fir)?.computePartialExpansion(useSiteSession, supertypeSupplier) ?: return
expansion.lookupTag.toSymbol(useSiteSession)
?.collectSuperTypes(list, visitedSymbols, deep, lookupInterfaces, useSiteSession, supertypeSupplier)
} }
else -> error("?!id:1") 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) { return when (this) {
RAW_FIR -> throw AssertionError("Raw FIR building phase does not have a transformer") RAW_FIR -> throw AssertionError("Raw FIR building phase does not have a transformer")
IMPORTS -> FirImportResolveTransformer() IMPORTS -> FirImportResolveTransformer()
SUPER_TYPES -> FirSupertypeResolverTransformer() SUPER_TYPES -> FirSupertypeResolverTransformerAdapter()
SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsTransformer() SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsTransformer()
TYPES -> FirTypeResolveTransformer() TYPES -> FirTypeResolveTransformer()
STATUS -> FirStatusResolveTransformer() STATUS -> FirStatusResolveTransformer()
IMPLICIT_TYPES_BODY_RESOLVE -> FirImplicitTypeBodyResolveTransformerAdapter() IMPLICIT_TYPES_BODY_RESOLVE -> FirImplicitTypeBodyResolveTransformerAdapter()
BODY_RESOLVE -> FirBodyResolveTransformerAdapter() BODY_RESOLVE -> FirBodyResolveTransformerAdapter()
} }
} }
@@ -11,7 +11,15 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.scopes.impl.*
fun MutableList<FirScope>.addImportingScopes(file: FirFile, session: FirSession, scopeSession: ScopeSession) { 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 // from low priority to high priority
FirDefaultStarImportingScope(session, scopeSession, priority = DefaultImportPriority.LOW), FirDefaultStarImportingScope(session, scopeSession, priority = DefaultImportPriority.LOW),
FirDefaultStarImportingScope(session, scopeSession, priority = DefaultImportPriority.HIGH), FirDefaultStarImportingScope(session, scopeSession, priority = DefaultImportPriority.HIGH),
@@ -1,5 +1,5 @@
FILE: fakeRecursiveSupertype.kt 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| { public constructor(): R|My| {
super<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| { public constructor(): R|His| {
super<R|Your|>() super<R|Your|>()
} }
@@ -1,3 +1,3 @@
FILE: fakeRecursiveTypealias.kt FILE: fakeRecursiveTypealias.kt
public final typealias My = R|class error: Symbol not found, for `incorrect.directory.My`| 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|>() super<R|J1|>()
} }
public final class Q { public final class Q : R|class error: Symbol not found, for `Nested`| {
public constructor(): R|K2.Q| { public constructor(): R|K2.Q| {
super<R|class error: Symbol not found, for `Nested`|>() super<R|class error: Symbol not found, for `Nested`|>()
} }