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.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")
|
||||||
}
|
}
|
||||||
|
|||||||
+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) {
|
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|
|
||||||
|
|||||||
+1
-1
@@ -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`|>()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user