FIR: Rewrite supertype resolution
This commit is contained in:
@@ -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")
|
||||
}
|
||||
|
||||
+424
@@ -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)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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|
|
||||
|
||||
+1
-1
@@ -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`|>()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user