FIR: Add possibility to run SupertypeResolverTransformer ad-hoc

This commit is contained in:
Denis Zharkov
2019-08-27 20:10:19 +03:00
parent d9d6c38c2b
commit 122c229a8b
5 changed files with 124 additions and 23 deletions
@@ -22,12 +22,14 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.classId
import org.jetbrains.kotlin.fir.declarations.superConeTypes
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.directExpansionType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.FirSupertypeResolverTransformer
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
@@ -94,14 +96,16 @@ class FirJavaElementFinder(
firClass.typeParameters.map { Pair(it.name.asString(), arrayOf(CommonClassNames.JAVA_LANG_OBJECT)) }
)
if (firClass.superTypeRefs.any { it !is FirResolvedTypeRef }) {
firClass.setCallbackOnSupertypesComputed {
stub.addSupertypesReferencesLists(firClass, session)
if (firClass.supertypesComputationStatus != FirClassLikeDeclaration.SupertypesComputationStatus.COMPUTED) {
val firForSuperClassFile = firProvider.getFirClassifierContainerFile(classId)
FirSupertypeResolverTransformer().apply {
initFromFile(firForSuperClassFile)
transformRegularClass(firClass, null)
}
} else {
stub.addSupertypesReferencesLists(firClass, session)
}
stub.addSupertypesReferencesLists(firClass, session)
for (nestedClass in firClass.declarations.filterIsInstance<FirRegularClass>()) {
buildStub(nestedClass, stub)
}
@@ -133,6 +137,7 @@ private fun FirRegularClass.packFlags(): Int {
}
private fun PsiClassStubImpl<*>.addSupertypesReferencesLists(firRegularClass: FirRegularClass, session: FirSession) {
if (firRegularClass.supertypesComputationStatus == FirClassLikeDeclaration.SupertypesComputationStatus.COMPUTING) return
require(firRegularClass.superTypeRefs.all { it is FirResolvedTypeRef }) {
"Supertypes for light class $qualifiedName are being added too early"
}
@@ -10,6 +10,7 @@ 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.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.scopes.FirPosition
@@ -26,14 +27,16 @@ import org.jetbrains.kotlin.name.ClassId
class FirSupertypeResolverTransformer : FirAbstractTreeTransformer(phase = FirResolvePhase.SUPER_TYPES) {
override lateinit var session: FirSession
private val currentlyComputing: MutableSet<ClassId> = mutableSetOf()
private val fullyComputed: MutableSet<ClassId> = mutableSetOf()
private lateinit var file: FirFile
override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult<FirFile> {
initFromFile(file)
return super.transformFile(file, data)
}
fun initFromFile(file: FirFile) {
session = file.fileSession
this.file = file
return super.transformFile(file, data)
}
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult<FirDeclaration> {
@@ -62,11 +65,13 @@ class FirSupertypeResolverTransformer : FirAbstractTreeTransformer(phase = FirRe
}
private fun resolveSupertypesOrExpansions(classLikeDeclaration: FirClassLikeDeclaration<*>): FirDeclaration {
if (classLikeDeclaration.areSupertypesComputed() || classLikeDeclaration.areSupertypesComputing()) {
return classLikeDeclaration
}
val classId = classLikeDeclaration.symbol.classId
if (classId in fullyComputed) return classLikeDeclaration
val visitor = ResolveSuperTypesTask(session, classId, file, currentlyComputing, fullyComputed, classLikeDeclaration)
val visitor = ResolveSuperTypesTask(session, classId, file, classLikeDeclaration)
file.accept(visitor, null).single
return visitor.resultingClass
@@ -76,8 +81,6 @@ class FirSupertypeResolverTransformer : FirAbstractTreeTransformer(phase = FirRe
override val session: FirSession,
private val requestedClassId: ClassId,
file: FirFile,
private val currentlyComputing: MutableSet<ClassId>,
private val fullyComputed: MutableSet<ClassId>,
private val knownFirClassLikeDeclaration: FirClassLikeDeclaration<*>? = null
) : FirAbstractTreeTransformerWithSuperTypes(phase = FirResolvePhase.SUPER_TYPES, reversedScopePriority = true) {
@@ -92,14 +95,14 @@ class FirSupertypeResolverTransformer : FirAbstractTreeTransformer(phase = FirRe
val classId = regularClass.classId
if (!isOuterClass(classId, requestedClassId)) return regularClass.compose()
val transformedClass = withScopeCleanup {
if (classId in fullyComputed) return@withScopeCleanup regularClass
if (regularClass.areSupertypesComputed() || regularClass.areSupertypesComputing()) 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)
val resultingTypeRefs = resolveLoops(regularClass, classId, resolvedTypesRefs)
regularClass.replaceSupertypes(resultingTypeRefs)
}
@@ -119,14 +122,14 @@ class FirSupertypeResolverTransformer : FirAbstractTreeTransformer(phase = FirRe
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: Nothing?): CompositeTransformResult<FirDeclaration> {
val classId = typeAlias.symbol.classId
// nested type aliases
if (classId in fullyComputed || !typeAlias.matchesRequestedDeclaration()) return typeAlias.compose()
if (typeAlias.areSupertypesComputed() || !typeAlias.matchesRequestedDeclaration()) 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()
val resultingTypeRef = resolveLoops(typeAlias, classId, listOf(resolvedTypesRef)).firstOrNull()
typeAlias.replaceExpandTypeRef(resultingTypeRef ?: resolvedTypesRef).also {
resultingClass = it
@@ -135,17 +138,18 @@ class FirSupertypeResolverTransformer : FirAbstractTreeTransformer(phase = FirRe
}
private fun resolveLoops(
firClassLikeDeclaration: FirClassLikeDeclaration<*>,
classId: ClassId,
resolvedTypesRefs: List<FirTypeRef>
): List<FirTypeRef> {
currentlyComputing.add(classId)
firClassLikeDeclaration.supertypesComputationStatus = FirClassLikeDeclaration.SupertypesComputationStatus.COMPUTING
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)) {
if (superTypeClassId.outerClasses().any { it.areSupertypesComputing() }) {
resultingTypeRefs.add(
FirErrorTypeRefImpl(superTypeRef.psi, "Recursion detected: ${superTypeRef.render()}")
)
@@ -170,19 +174,22 @@ class FirSupertypeResolverTransformer : FirAbstractTreeTransformer(phase = FirRe
val firForSuperClassFile = provider.getFirClassifierContainerFile(superTypeClassId)
ResolveSuperTypesTask(
sessionForSupertype, superTypeClassId, firForSuperClassFile,
currentlyComputing, fullyComputed
sessionForSupertype, superTypeClassId, firForSuperClassFile
).transformFile(firForSuperClassFile, null)
}
resultingTypeRefs.add(superTypeRef)
}
fullyComputed.add(classId)
currentlyComputing.remove(classId)
firClassLikeDeclaration.supertypesComputationStatus = FirClassLikeDeclaration.SupertypesComputationStatus.COMPUTED
return resultingTypeRefs
}
private fun ClassId.areSupertypesComputing(): Boolean {
val fir = session.firSymbolProvider.getClassLikeSymbolByFqName(this)?.fir ?: return false
return fir.areSupertypesComputing()
}
private fun resolveNestedClassesSupertypes(
regularClass: FirRegularClass,
data: Nothing?
@@ -212,3 +219,8 @@ private fun isOuterClass(outerCandidate: ClassId, innerCandidate: ClassId) =
innerCandidate.outerClasses().any { outerCandidate == it }
private fun ClassId.outerClasses() = generateSequence(this, ClassId::getOuterClassId)
private fun FirClassLikeDeclaration<*>.areSupertypesComputed() =
supertypesComputationStatus == FirClassLikeDeclaration.SupertypesComputationStatus.COMPUTED
private fun FirClassLikeDeclaration<*>.areSupertypesComputing() =
supertypesComputationStatus == FirClassLikeDeclaration.SupertypesComputationStatus.COMPUTING
@@ -0,0 +1,33 @@
// FILE: K1.kt
class K2: J1() {
class Q : Nested()
fun bar() {
foo()
baz()
superClass()
superI()
}
}
// FILE: J1.java
public class J1 extends K2() {
public class Nested {}
void baz() {}
}
// FILE: K2.kt
open class KFirst : SuperClass(), SuperI {
fun foo() {
}
}
// FILE: K3.kt
abstract class SuperClass {
fun superClass() {}
}
interface SuperI {
fun superI() {}
}
@@ -0,0 +1,46 @@
FILE: K1.kt
public final class K2 : R|J1| {
public constructor(): R|K2| {
super<R|J1|>()
}
public final class Q {
public constructor(): R|K2.Q| {
super<R|class error: Symbol not found, for `Nested`|>()
}
}
public final fun bar(): R|kotlin/Unit| {
<Unresolved name: foo>#()
<Unresolved name: baz>#()
<Unresolved name: superClass>#()
<Unresolved name: superI>#()
}
}
FILE: K2.kt
public open class KFirst : R|SuperClass|, R|SuperI| {
public constructor(): R|KFirst| {
super<R|SuperClass|>()
}
public final fun foo(): R|kotlin/Unit| {
}
}
FILE: K3.kt
public abstract class SuperClass : R|kotlin/Any| {
public constructor(): R|SuperClass| {
super<R|kotlin/Any|>()
}
public final fun superClass(): R|kotlin/Unit| {
}
}
public abstract interface SuperI : R|kotlin/Any| {
public open fun superI(): R|kotlin/Unit| {
}
}
@@ -46,6 +46,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchy.kt");
}
@TestMetadata("KJKComplexHierarchyNestedLoop.kt")
public void testKJKComplexHierarchyNestedLoop() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyNestedLoop.kt");
}
@TestMetadata("KJKComplexHierarchyWithNested.kt")
public void testKJKComplexHierarchyWithNested() throws Exception {
runTest("compiler/fir/resolve/testData/diagnostics/j+k/KJKComplexHierarchyWithNested.kt");