Extract supertypes resolution into a separate FIR phase
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.resolve
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.toFirClassLike
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -27,6 +28,9 @@ interface FirSymbolProvider {
|
||||
|
||||
fun getPackage(fqName: FqName): FqName? // TODO: Replace to symbol sometime
|
||||
|
||||
// TODO: should not retrieve session through the FirElement::session
|
||||
fun getSessionForClass(classId: ClassId): FirSession? = getClassLikeSymbolByFqName(classId)?.toFirClassLike()?.session
|
||||
|
||||
companion object {
|
||||
fun getInstance(session: FirSession) = session.service<FirSymbolProvider>()
|
||||
}
|
||||
|
||||
+9
@@ -7,11 +7,13 @@ package org.jetbrains.kotlin.fir.resolve.transformers
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.superConeTypes
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
@@ -100,4 +102,11 @@ abstract class FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority: B
|
||||
else -> error("?!id:1")
|
||||
}
|
||||
}
|
||||
|
||||
protected fun FirMemberDeclaration.addTypeParametersScope() {
|
||||
val scopes = towerScope.scopes
|
||||
if (typeParameters.isNotEmpty()) {
|
||||
scopes += FirMemberTypeParameterScope(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedFunctionTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||
import org.jetbrains.kotlin.fir.visitors.compose
|
||||
|
||||
class FirSpecificTypeResolverTransformer(
|
||||
private val towerScope: FirScope,
|
||||
private val position: FirPosition,
|
||||
private val session: FirSession
|
||||
) : FirAbstractTreeTransformer() {
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: Nothing?): CompositeTransformResult<FirTypeRef> {
|
||||
val typeResolver = FirTypeResolver.getInstance(session)
|
||||
typeRef.transformChildren(FirSpecificTypeResolverTransformer(towerScope, FirPosition.OTHER, session), null)
|
||||
return transformType(typeRef, typeResolver.resolveType(typeRef, towerScope, position))
|
||||
}
|
||||
|
||||
override fun transformFunctionTypeRef(functionTypeRef: FirFunctionTypeRef, data: Nothing?): CompositeTransformResult<FirTypeRef> {
|
||||
val typeResolver = FirTypeResolver.getInstance(functionTypeRef.session)
|
||||
functionTypeRef.transformChildren(this, data)
|
||||
return FirResolvedFunctionTypeRefImpl(
|
||||
functionTypeRef.psi,
|
||||
functionTypeRef.session,
|
||||
functionTypeRef.isMarkedNullable,
|
||||
functionTypeRef.annotations as MutableList<FirAnnotationCall>,
|
||||
functionTypeRef.receiverTypeRef,
|
||||
functionTypeRef.valueParameters as MutableList<FirValueParameter>,
|
||||
functionTypeRef.returnTypeRef,
|
||||
typeResolver.resolveType(functionTypeRef, towerScope, position)
|
||||
).compose()
|
||||
}
|
||||
|
||||
private fun transformType(typeRef: FirTypeRef, resolvedType: ConeKotlinType): CompositeTransformResult<FirTypeRef> {
|
||||
return FirResolvedTypeRefImpl(
|
||||
typeRef.session,
|
||||
typeRef.psi,
|
||||
resolvedType,
|
||||
false,
|
||||
typeRef.annotations
|
||||
).compose()
|
||||
}
|
||||
|
||||
override fun transformResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: Nothing?): CompositeTransformResult<FirTypeRef> {
|
||||
return resolvedTypeRef.compose()
|
||||
}
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||
import org.jetbrains.kotlin.fir.visitors.compose
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
class FirSupertypeResolverTransformer : FirAbstractTreeTransformer() {
|
||||
private lateinit var firSession: FirSession
|
||||
private val currentlyComputing: MutableSet<ClassId> = mutableSetOf()
|
||||
private val fullyComputed: MutableSet<ClassId> = mutableSetOf()
|
||||
|
||||
override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult<FirFile> {
|
||||
firSession = file.session
|
||||
return super.transformFile(file, data)
|
||||
}
|
||||
|
||||
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult<FirDeclaration> {
|
||||
val transformedClass = resolveSupertypesOrExpansions(regularClass) as? FirRegularClass ?: regularClass
|
||||
|
||||
// resolve supertypes for nested classes
|
||||
return super.transformRegularClass(transformedClass, data)
|
||||
}
|
||||
|
||||
|
||||
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: Nothing?): CompositeTransformResult<FirDeclaration> {
|
||||
return resolveSupertypesOrExpansions(typeAlias).compose()
|
||||
}
|
||||
|
||||
private fun resolveSupertypesOrExpansions(classLikeDeclaration: FirClassLikeDeclaration): FirDeclaration {
|
||||
val classId = classLikeDeclaration.symbol.classId
|
||||
|
||||
if (classId in fullyComputed) return classLikeDeclaration
|
||||
|
||||
val firFile = firSession.getService(FirProvider::class).getFirClassifierContainerFile(classId)
|
||||
|
||||
val visitor = ResolveSuperTypesTask(firSession, classId, firFile, currentlyComputing, fullyComputed)
|
||||
firFile.accept(visitor, null).single
|
||||
|
||||
return visitor.resultingClass
|
||||
}
|
||||
|
||||
private class ResolveSuperTypesTask(
|
||||
private val session: FirSession,
|
||||
private val requestedClassId: ClassId,
|
||||
file: FirFile,
|
||||
private val currentlyComputing: MutableSet<ClassId>,
|
||||
private val fullyComputed: MutableSet<ClassId>
|
||||
) : FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority = true) {
|
||||
|
||||
lateinit var resultingClass: FirDeclaration
|
||||
|
||||
init {
|
||||
towerScope.addImportingScopes(file, session)
|
||||
}
|
||||
|
||||
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult<FirDeclaration> {
|
||||
val classId = regularClass.classId
|
||||
if (!isOuterClass(classId, requestedClassId)) return regularClass.compose()
|
||||
val transformedClass = withScopeCleanup {
|
||||
if (classId in fullyComputed) return@withScopeCleanup regularClass
|
||||
|
||||
regularClass.addTypeParametersScope()
|
||||
|
||||
val transformer = FirSpecificTypeResolverTransformer(towerScope, FirPosition.SUPER_TYPE_OR_EXPANSION, session)
|
||||
val resolvedTypesRefs = regularClass.superTypeRefs.map { transformer.transformTypeRef(it, data).single }
|
||||
|
||||
val resultingTypeRefs = resolveLoops(classId, resolvedTypesRefs)
|
||||
regularClass.replaceSupertypes(resultingTypeRefs)
|
||||
}
|
||||
|
||||
if (classId == requestedClassId) {
|
||||
resultingClass = transformedClass
|
||||
return transformedClass.compose()
|
||||
}
|
||||
|
||||
return resolveNestedClassesSupertypes(transformedClass, data)
|
||||
}
|
||||
|
||||
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: Nothing?): CompositeTransformResult<FirDeclaration> {
|
||||
val classId = typeAlias.symbol.classId
|
||||
// nested type aliases
|
||||
if (requestedClassId != classId || classId in fullyComputed) return typeAlias.compose()
|
||||
|
||||
return withScopeCleanup {
|
||||
typeAlias.addTypeParametersScope()
|
||||
|
||||
val transformer = FirSpecificTypeResolverTransformer(towerScope, FirPosition.SUPER_TYPE_OR_EXPANSION, session)
|
||||
val resolvedTypesRef = transformer.transformTypeRef(typeAlias.expandedTypeRef, data).single
|
||||
val resultingTypeRef = resolveLoops(classId, listOf(resolvedTypesRef)).firstOrNull()
|
||||
|
||||
typeAlias.replaceExpandTypeRef(resultingTypeRef ?: resolvedTypesRef).also {
|
||||
resultingClass = it
|
||||
}
|
||||
}.compose()
|
||||
}
|
||||
|
||||
private fun resolveLoops(
|
||||
classId: ClassId,
|
||||
resolvedTypesRefs: List<FirTypeRef>
|
||||
): List<FirTypeRef> {
|
||||
currentlyComputing.add(classId)
|
||||
|
||||
val resultingTypeRefs = mutableListOf<FirTypeRef>()
|
||||
for (superTypeRef in resolvedTypesRefs) {
|
||||
val resolvedType = superTypeRef.coneTypeSafe<ConeClassLikeType>() ?: continue
|
||||
val superTypeClassId = resolvedType.lookupTag.classId
|
||||
|
||||
if (superTypeClassId.outerClasses().any(currentlyComputing::contains)) {
|
||||
resultingTypeRefs.add(
|
||||
FirErrorTypeRefImpl(session, superTypeRef.psi, "Recursion detected: ${superTypeRef.render()}")
|
||||
)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
val sessionForSupertype = session.getService(FirSymbolProvider::class).getSessionForClass(superTypeClassId) ?: continue
|
||||
val provider = sessionForSupertype.getService(FirProvider::class)
|
||||
|
||||
val firClassForSupertype =
|
||||
sessionForSupertype
|
||||
.getService(FirSymbolProvider::class)
|
||||
.getClassLikeSymbolByFqName(superTypeClassId)
|
||||
?.toFirClassLike() as? FirClass
|
||||
|
||||
// TODO: this if is a temporary hack for built-in types (because we can't load file for them)
|
||||
if (firClassForSupertype == null || firClassForSupertype.superTypeRefs.any { it !is FirResolvedTypeRef }) {
|
||||
val firForSuperClassFile = provider.getFirClassifierContainerFile(superTypeClassId)
|
||||
|
||||
ResolveSuperTypesTask(
|
||||
sessionForSupertype, superTypeClassId, firForSuperClassFile,
|
||||
currentlyComputing, fullyComputed
|
||||
).transformFile(firForSuperClassFile, null)
|
||||
}
|
||||
|
||||
resultingTypeRefs.add(superTypeRef)
|
||||
}
|
||||
|
||||
fullyComputed.add(classId)
|
||||
currentlyComputing.remove(classId)
|
||||
return resultingTypeRefs
|
||||
}
|
||||
|
||||
private fun resolveNestedClassesSupertypes(
|
||||
regularClass: FirRegularClass,
|
||||
data: Nothing?
|
||||
): CompositeTransformResult<FirDeclaration> {
|
||||
return withScopeCleanup {
|
||||
val session = regularClass.session
|
||||
val firProvider = FirProvider.getInstance(session)
|
||||
val classId = regularClass.symbol.classId
|
||||
lookupSuperTypes(regularClass, lookupInterfaces = false, deep = true, useSiteSession = session)
|
||||
.asReversed().mapTo(towerScope.scopes) {
|
||||
FirNestedClassifierScope(it.lookupTag.classId, FirSymbolProvider.getInstance(session))
|
||||
}
|
||||
val companionObjects = regularClass.declarations.filterIsInstance<FirRegularClass>().filter { it.isCompanion }
|
||||
for (companionObject in companionObjects) {
|
||||
towerScope.scopes += FirNestedClassifierScope(companionObject.symbol.classId, firProvider)
|
||||
}
|
||||
towerScope.scopes += FirNestedClassifierScope(classId, firProvider)
|
||||
regularClass.addTypeParametersScope()
|
||||
|
||||
super.transformRegularClass(regularClass, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isOuterClass(outerCandidate: ClassId, innerCandidate: ClassId) =
|
||||
innerCandidate.outerClasses().any { outerCandidate == it }
|
||||
|
||||
private fun ClassId.outerClasses() = generateSequence(this, ClassId::getOuterClassId)
|
||||
+2
-7
@@ -12,17 +12,12 @@ class FirTotalResolveTransformer {
|
||||
|
||||
val transformers: List<FirTransformer<Nothing?>> = listOf(
|
||||
FirImportResolveTransformer(),
|
||||
FirSupertypeResolverTransformer(),
|
||||
FirTypeResolveTransformer(),
|
||||
FirStatusResolveTransformer(),
|
||||
FirAccessResolveTransformer()
|
||||
)
|
||||
|
||||
fun processFile(firFile: FirFile) {
|
||||
for (transformer in transformers) {
|
||||
firFile.transform<FirFile, Nothing?>(transformer, null)
|
||||
}
|
||||
}
|
||||
|
||||
fun processFiles(files: List<FirFile>) {
|
||||
for (transformer in transformers) {
|
||||
for (firFile in files) {
|
||||
@@ -30,4 +25,4 @@ class FirTotalResolveTransformer {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-156
@@ -5,68 +5,35 @@
|
||||
|
||||
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.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirTypeResolver
|
||||
import org.jetbrains.kotlin.fir.scopes.FirPosition
|
||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.transformSingle
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedFunctionTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.compose
|
||||
|
||||
open class FirTypeResolveTransformer(
|
||||
private val traversedClassifiers: Set<FirMemberDeclaration> = setOf()
|
||||
) : FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority = true) {
|
||||
private lateinit var firProvider: FirProvider
|
||||
open class FirTypeResolveTransformer : FirAbstractTreeTransformerWithSuperTypes(reversedScopePriority = true) {
|
||||
private lateinit var session: FirSession
|
||||
|
||||
override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult<FirFile> {
|
||||
val session = file.session
|
||||
firProvider = session.getService(FirProvider::class)
|
||||
session = file.session
|
||||
return withScopeCleanup {
|
||||
towerScope.scopes += listOf(
|
||||
// from low priority to high priority
|
||||
FirDefaultStarImportingScope(session),
|
||||
FirExplicitStarImportingScope(file.imports, session),
|
||||
FirDefaultSimpleImportingScope(session),
|
||||
FirSelfImportingScope(file.packageFqName, session),
|
||||
// TODO: explicit simple importing scope should have highest priority (higher than inner scopes added in process)
|
||||
FirExplicitSimpleImportingScope(file.imports, session)
|
||||
)
|
||||
towerScope.addImportingScopes(file, session)
|
||||
super.transformFile(file, data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveSuperTypesAndExpansions(element: FirMemberDeclaration) {
|
||||
try {
|
||||
element.transformChildren(SuperTypeResolver(traversedClassifiers + listOfNotNull(element)), null)
|
||||
} catch (e: Exception) {
|
||||
class SuperTypeResolveException(cause: Exception) : Exception(element.render(), cause)
|
||||
throw SuperTypeResolveException(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult<FirDeclaration> {
|
||||
withScopeCleanup {
|
||||
regularClass.addTypeParametersScope()
|
||||
resolveSuperTypesAndExpansions(regularClass)
|
||||
regularClass.typeParameters.forEach {
|
||||
it.accept(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
return withScopeCleanup {
|
||||
val session = regularClass.session
|
||||
val firProvider = FirProvider.getInstance(session)
|
||||
@@ -89,19 +56,11 @@ open class FirTypeResolveTransformer(
|
||||
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: Nothing?): CompositeTransformResult<FirDeclaration> {
|
||||
return withScopeCleanup {
|
||||
typeAlias.addTypeParametersScope()
|
||||
resolveSuperTypesAndExpansions(typeAlias)
|
||||
super.transformTypeAlias(typeAlias, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun FirMemberDeclaration.addTypeParametersScope() {
|
||||
val scopes = towerScope.scopes
|
||||
if (typeParameters.isNotEmpty()) {
|
||||
scopes += FirMemberTypeParameterScope(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun transformProperty(property: FirProperty, data: Nothing?): CompositeTransformResult<FirDeclaration> {
|
||||
return withScopeCleanup {
|
||||
property.addTypeParametersScope()
|
||||
@@ -117,112 +76,6 @@ open class FirTypeResolveTransformer(
|
||||
}
|
||||
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: Nothing?): CompositeTransformResult<FirTypeRef> {
|
||||
val typeResolver = FirTypeResolver.getInstance(typeRef.session)
|
||||
typeRef.transformChildren(this, null)
|
||||
return transformType(typeRef, typeResolver.resolveType(typeRef, towerScope, position = FirPosition.OTHER))
|
||||
}
|
||||
|
||||
override fun transformFunctionTypeRef(functionTypeRef: FirFunctionTypeRef, data: Nothing?): CompositeTransformResult<FirTypeRef> {
|
||||
val typeResolver = FirTypeResolver.getInstance(functionTypeRef.session)
|
||||
functionTypeRef.transformChildren(this, data)
|
||||
return FirResolvedFunctionTypeRefImpl(
|
||||
functionTypeRef.psi,
|
||||
functionTypeRef.session,
|
||||
functionTypeRef.isMarkedNullable,
|
||||
functionTypeRef.annotations as MutableList<FirAnnotationCall>,
|
||||
functionTypeRef.receiverTypeRef,
|
||||
functionTypeRef.valueParameters as MutableList<FirValueParameter>,
|
||||
functionTypeRef.returnTypeRef,
|
||||
typeResolver.resolveType(functionTypeRef, towerScope, FirPosition.OTHER)
|
||||
).compose()
|
||||
}
|
||||
|
||||
private fun transformType(typeRef: FirTypeRef, resolvedType: ConeKotlinType): CompositeTransformResult<FirTypeRef> {
|
||||
return FirResolvedTypeRefImpl(
|
||||
typeRef.session,
|
||||
typeRef.psi,
|
||||
resolvedType,
|
||||
false,
|
||||
typeRef.annotations
|
||||
).compose()
|
||||
}
|
||||
|
||||
override fun transformResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: Nothing?): CompositeTransformResult<FirTypeRef> {
|
||||
return resolvedTypeRef.compose()
|
||||
}
|
||||
|
||||
override fun transformValueParameter(valueParameter: FirValueParameter, data: Nothing?): CompositeTransformResult<FirDeclaration> {
|
||||
return valueParameter.also { it.transformChildren(this, data) }.compose()
|
||||
}
|
||||
|
||||
|
||||
override fun transformTypeProjectionWithVariance(
|
||||
typeProjectionWithVariance: FirTypeProjectionWithVariance,
|
||||
data: Nothing?
|
||||
): CompositeTransformResult<FirTypeProjection> {
|
||||
typeProjectionWithVariance.transformChildren(this, data)
|
||||
return typeProjectionWithVariance.compose()
|
||||
}
|
||||
|
||||
private class SuperTypeResolveTransformer(
|
||||
val elementIterator: Iterator<FirElement>,
|
||||
traversedClassifiers: Set<FirMemberDeclaration>
|
||||
) : FirTypeResolveTransformer(traversedClassifiers) {
|
||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||
if (elementIterator.hasNext()) elementIterator.next().transformSingle(this, data)
|
||||
return element.compose()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class SuperTypeResolver(val traversedClassifiers: Set<FirMemberDeclaration>) : FirTransformer<Nothing?>() {
|
||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
|
||||
return element.compose()
|
||||
}
|
||||
|
||||
|
||||
private fun walkSymbols(symbol: ConeClassifierSymbol) {
|
||||
if (symbol !is ConeClassLikeSymbol || symbol !is FirBasedSymbol<*>) return
|
||||
val classId = symbol.classId
|
||||
val classes = generateSequence(classId) { it.outerClassId }.toList().asReversed()
|
||||
|
||||
val fir = symbol.fir
|
||||
if (fir is FirTypeAlias) {
|
||||
if (fir.expandedTypeRef is FirResolvedTypeRef) return
|
||||
} else if (fir is FirClass) {
|
||||
if (fir.superTypeRefs.all { it is FirResolvedTypeRef }) return
|
||||
}
|
||||
|
||||
val firProvider = fir.session.service<FirProvider>()
|
||||
val file = firProvider.getFirClassifierContainerFile(classes.first())
|
||||
|
||||
val firElementsToVisit = classes.asSequence().map {
|
||||
firProvider.getFirClassifierByFqName(it)!!
|
||||
}
|
||||
|
||||
val transformer = SuperTypeResolveTransformer(
|
||||
firElementsToVisit.iterator(), traversedClassifiers
|
||||
)
|
||||
file.transformSingle(transformer, null)
|
||||
}
|
||||
|
||||
override fun transformTypeRef(typeRef: FirTypeRef, data: Nothing?): CompositeTransformResult<FirTypeRef> {
|
||||
val typeResolver = FirTypeResolver.getInstance(typeRef.session)
|
||||
val symbol = typeResolver.resolveToSymbol(typeRef, towerScope, position = FirPosition.SUPER_TYPE_OR_EXPANSION)
|
||||
val myTransformer = this@FirTypeResolveTransformer
|
||||
|
||||
if (symbol != null) {
|
||||
if (symbol is AbstractFirBasedSymbol<*> && symbol.fir in traversedClassifiers) {
|
||||
return FirErrorTypeRefImpl(typeRef.session, typeRef.psi, "Recursion detected: ${typeRef.render()}").compose()
|
||||
} else {
|
||||
walkSymbols(symbol)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeRef !is FirUserTypeRef) return typeRef.transform(myTransformer, data)
|
||||
|
||||
|
||||
typeRef.transformChildren(myTransformer, null)
|
||||
return myTransformer.transformType(typeRef, typeResolver.resolveUserType(typeRef, symbol, towerScope))
|
||||
}
|
||||
return FirSpecificTypeResolverTransformer(towerScope, FirPosition.OTHER, session).transformTypeRef(typeRef, data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.scopes
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
|
||||
fun FirCompositeScope.addImportingScopes(file: FirFile, session: FirSession) {
|
||||
scopes += listOf(
|
||||
// from low priority to high priority
|
||||
FirDefaultStarImportingScope(session),
|
||||
FirExplicitStarImportingScope(file.imports, session),
|
||||
FirDefaultSimpleImportingScope(session),
|
||||
FirSelfImportingScope(file.packageFqName, session),
|
||||
// TODO: explicit simple importing scope should have highest priority (higher than inner scopes added in process)
|
||||
FirExplicitSimpleImportingScope(file.imports, session)
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
FILE: fakeRecursiveSupertype.kt
|
||||
public final class My : R|error: Recursion detected: My| {
|
||||
public final class My : R|error: Recursion detected: R|My|| {
|
||||
public constructor(): super<R|My|>()
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@ FILE: fakeRecursiveSupertype.kt
|
||||
public constructor(): super<R|His|>()
|
||||
|
||||
}
|
||||
public final class His : R|error: Recursion detected: Your| {
|
||||
public final class His : R|error: Recursion detected: R|Your|| {
|
||||
public constructor(): super<R|Your|>()
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
FILE: fakeRecursiveTypealias.kt
|
||||
public final typealias My = R|error: Symbol not found, for `incorrect.directory.My`|
|
||||
public final typealias Your = R|error: Recursion detected: Your|
|
||||
public final typealias Your = R|error: Recursion detected: R|Your||
|
||||
|
||||
@@ -28,8 +28,9 @@ interface FirElement {
|
||||
fun acceptChildren(visitor: FirVisitorVoid) =
|
||||
acceptChildren(visitor, null)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <E : FirElement, D> transform(visitor: FirTransformer<D>, data: D): CompositeTransformResult<E> =
|
||||
CompositeTransformResult(accept(visitor, data))
|
||||
accept(visitor, data) as CompositeTransformResult<E>
|
||||
|
||||
fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement = this
|
||||
}
|
||||
}
|
||||
|
||||
+11
-1
@@ -5,8 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.declarations
|
||||
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
|
||||
interface FirClassLikeDeclaration : FirMemberDeclaration {
|
||||
val symbol: ConeClassifierSymbol
|
||||
val symbol: ConeClassLikeSymbol
|
||||
}
|
||||
|
||||
fun ConeClassifierSymbol.toFirClassLike(): FirClassLikeDeclaration? =
|
||||
when (this) {
|
||||
is FirClassSymbol -> this.fir
|
||||
is FirTypeAliasSymbol -> this.fir
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.BaseTransformedType
|
||||
import org.jetbrains.kotlin.fir.VisitedSupertype
|
||||
import org.jetbrains.kotlin.fir.symbols.FirSymbolOwner
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
|
||||
// May be all containers should be properties and not base classes
|
||||
@@ -32,4 +33,8 @@ interface FirRegularClass : FirClass, @VisitedSupertype FirClassLikeDeclaration,
|
||||
super<FirClassLikeDeclaration>.acceptChildren(visitor, data)
|
||||
super<FirClass>.acceptChildren(visitor, data)
|
||||
}
|
||||
|
||||
fun replaceSupertypes(newSupertypes: List<FirTypeRef>): FirRegularClass
|
||||
}
|
||||
|
||||
val FirRegularClass.classId get() = symbol.classId
|
||||
|
||||
@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
|
||||
interface FirTypeAlias : FirClassLikeDeclaration, FirSymbolOwner<FirTypeAlias> {
|
||||
fun replaceExpandTypeRef(typeRef: FirTypeRef): FirTypeAlias
|
||||
|
||||
val expandedTypeRef: FirTypeRef
|
||||
|
||||
override val symbol: FirTypeAliasSymbol
|
||||
|
||||
@@ -10,13 +10,13 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.transformInplace
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
open class FirClassImpl(
|
||||
session: FirSession,
|
||||
@@ -46,6 +46,11 @@ open class FirClassImpl(
|
||||
|
||||
override val declarations = mutableListOf<FirDeclaration>()
|
||||
|
||||
override fun replaceSupertypes(newSupertypes: List<FirTypeRef>): FirRegularClass {
|
||||
superTypeRefs.clear()
|
||||
superTypeRefs.addAll(newSupertypes)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirRegularClass {
|
||||
superTypeRefs.transformInplace(transformer, data)
|
||||
@@ -55,4 +60,4 @@ open class FirClassImpl(
|
||||
declarations.transformInplace(transformer, data)
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -32,9 +32,14 @@ class FirTypeAliasImpl(
|
||||
symbol.bind(this)
|
||||
}
|
||||
|
||||
override fun replaceExpandTypeRef(typeRef: FirTypeRef): FirTypeAlias {
|
||||
expandedTypeRef = typeRef
|
||||
return this
|
||||
}
|
||||
|
||||
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement {
|
||||
expandedTypeRef = expandedTypeRef.transformSingle(transformer, data)
|
||||
|
||||
return super<FirAbstractMemberDeclaration>.transformChildren(transformer, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -7,8 +7,7 @@ package org.jetbrains.kotlin.fir.visitors
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
|
||||
@Suppress("UNSUPPORTED_FEATURE")
|
||||
inline class CompositeTransformResult<out T : Any>(val a: Any) {
|
||||
class CompositeTransformResult<out T : Any>(val a: Any) {
|
||||
|
||||
companion object {
|
||||
fun <T : Any> empty() = CompositeTransformResult<T>(emptyList<T>())
|
||||
@@ -33,4 +32,4 @@ inline class CompositeTransformResult<out T : Any>(val a: Any) {
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun <T : FirElement> T.compose() = CompositeTransformResult.single(this)
|
||||
inline fun <T : FirElement> T.compose() = CompositeTransformResult.single(this)
|
||||
|
||||
+1
-1
@@ -24,4 +24,4 @@ class D : A() {
|
||||
bar()
|
||||
baz()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,11 +106,11 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
|
||||
}
|
||||
|
||||
val transformer = FirTotalResolveTransformer()
|
||||
transformer.processFiles(firFiles)
|
||||
for (file in firFiles) {
|
||||
transformer.processFile(file)
|
||||
val firFileDump = StringBuilder().also { file.accept(FirRenderer(it), null) }.toString()
|
||||
val expectedPath = expectedTxtPath((file.psi as PsiFile).virtualFile)
|
||||
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user