[FIR] make FirJavaClass.superTypes to be lazily enhanced

This should solve the problem with deadlocks/performance in the K2 IDE

This is a temporary solution until the ^KT-55387 is properly fixed

^KT-55387
^KT-54890
This commit is contained in:
Ilya Kirillov
2022-12-27 17:15:28 +01:00
committed by teamcity
parent cf8b1692ca
commit ae68f08856
6 changed files with 77 additions and 64 deletions
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
@@ -24,21 +23,15 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildTypeParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.classId
import org.jetbrains.kotlin.fir.java.declarations.*
import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement
import org.jetbrains.kotlin.fir.resolve.constructType
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.load.java.FakePureImplementationsProvider
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.structure.*
@@ -181,59 +174,14 @@ abstract class FirJavaFacade(
// 1. Resolve annotations
// 2. Enhance type parameter bounds - may refer to each other, take default nullability from annotations
// 3. Enhance super types - may refer to type parameter bounds, take default nullability from annotations
// 3. (will happen lazily in FirJavaClass.superTypeRefs) Enhance super types - may refer to type parameter bounds, take default nullability from annotations
firJavaClass.setAnnotationsFromJava(session, javaClass, javaTypeParameterStack)
enhancement.enhanceTypeParameterBoundsAfterFirstRound(firJavaClass.typeParameters, initialBounds)
val enhancedSuperTypes = buildList {
val purelyImplementedSupertype = firJavaClass.getPurelyImplementedSupertype()
val purelyImplementedSupertypeClassId = purelyImplementedSupertype?.classId
firJavaClass.superTypeRefs.mapNotNullTo(this) { superType ->
enhancement.enhanceSuperType(superType).takeUnless {
purelyImplementedSupertypeClassId != null && it.coneType.classId == purelyImplementedSupertypeClassId
}
}
purelyImplementedSupertype?.let {
add(buildResolvedTypeRef { type = it })
}
}
firJavaClass.replaceSuperTypeRefs(enhancedSuperTypes)
firJavaClass.replaceDeprecationsProvider(firJavaClass.getDeprecationsProvider(session))
return firJavaClass
}
private fun FirJavaClass.getPurelyImplementedSupertype(): ConeKotlinType? {
val purelyImplementedClassIdFromAnnotation = annotations
.firstOrNull { it.classId?.asSingleFqName() == JvmAnnotationNames.PURELY_IMPLEMENTS_ANNOTATION }
?.let { (it.argumentMapping.mapping.values.firstOrNull() as? FirConstExpression<*>) }
?.let { it.value as? String }
?.takeIf { it.isNotBlank() && isValidJavaFqName(it) }
?.let { ClassId.topLevel(FqName(it)) }
val purelyImplementedClassId = purelyImplementedClassIdFromAnnotation
?: FakePureImplementationsProvider.getPurelyImplementedInterface(symbol.classId)
?: return null
val superTypeSymbol = session.symbolProvider.getClassLikeSymbolByClassId(purelyImplementedClassId) ?: return null
val superTypeParameterSymbols = superTypeSymbol.typeParameterSymbols ?: return null
val typeParameters = this.typeParameters
val supertypeParameterCount = superTypeParameterSymbols.size
val typeParameterCount = typeParameters.size
val parametersAsTypeProjections = when {
typeParameterCount == supertypeParameterCount ->
typeParameters.map { ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(it.symbol), isNullable = false) }
typeParameterCount == 1 && supertypeParameterCount > 1 && purelyImplementedClassIdFromAnnotation == null -> {
val projection = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(typeParameters.first().symbol), isNullable = false)
(1..supertypeParameterCount).map { projection }
}
else -> return null
}
return ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(purelyImplementedClassId),
parametersAsTypeProjections.toTypedArray(),
isNullable = false
)
}
private fun createFirJavaClass(
javaClass: JavaClass,
classSymbol: FirRegularClassSymbol,
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.FirRegularClassBuilder
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement
import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
@@ -44,7 +45,7 @@ class FirJavaClass @FirImplementationDetail internal constructor(
override val declarations: MutableList<FirDeclaration>,
override val scopeProvider: FirScopeProvider,
override val symbol: FirRegularClassSymbol,
override val superTypeRefs: MutableList<FirTypeRef>,
private val unenhnancedSuperTypes: List<FirTypeRef>,
override val typeParameters: MutableList<FirTypeParameterRef>,
internal val javaPackage: JavaPackage?,
val javaTypeParameterStack: JavaTypeParameterStack,
@@ -63,9 +64,14 @@ class FirJavaClass @FirImplementationDetail internal constructor(
override val attributes: FirDeclarationAttributes = FirDeclarationAttributes()
// TODO: the lazy superTypeRefs is a workaround for KT-55387, some non-lazy solution should probably be used instead
override val superTypeRefs: List<FirTypeRef> by lazy {
val enhancement = FirSignatureEnhancement(this@FirJavaClass, moduleData.session, overridden = { emptyList() })
enhancement.enhanceSuperTypes(unenhnancedSuperTypes)
}
override fun replaceSuperTypeRefs(newSuperTypeRefs: List<FirTypeRef>) {
superTypeRefs.clear()
superTypeRefs.addAll(newSuperTypeRefs)
error("${::replaceSuperTypeRefs.name} should not be called for ${this::class.simpleName}, ${superTypeRefs::class.simpleName} is lazily calulated")
}
override fun replaceResolvePhase(newResolvePhase: FirResolvePhase) {
@@ -101,7 +107,6 @@ class FirJavaClass @FirImplementationDetail internal constructor(
}
override fun <D> transformSuperTypeRefs(transformer: FirTransformer<D>, data: D): FirRegularClass {
superTypeRefs.transformInplace(transformer, data)
return this
}
@@ -152,6 +157,7 @@ class FirJavaClassBuilder : FirRegularClassBuilder(), FirAnnotationContainerBuil
@OptIn(FirImplementationDetail::class)
override fun build(): FirJavaClass {
@Suppress("UNCHECKED_CAST")
return FirJavaClass(
source,
moduleData,
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols
import org.jetbrains.kotlin.fir.caches.FirCache
import org.jetbrains.kotlin.fir.caches.FirCachesFactory
import org.jetbrains.kotlin.fir.caches.createCache
@@ -25,26 +26,31 @@ import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.classId
import org.jetbrains.kotlin.fir.java.FirJavaTypeConversionMode
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.java.declarations.*
import org.jetbrains.kotlin.fir.java.resolveIfJavaType
import org.jetbrains.kotlin.fir.java.symbols.FirJavaOverriddenSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.jvm.FirJavaTypeRef
import org.jetbrains.kotlin.load.java.AnnotationQualifierApplicabilityType
import org.jetbrains.kotlin.load.java.FakePureImplementationsProvider
import org.jetbrains.kotlin.load.java.JavaTypeQualifiersByElementType
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.typeEnhancement.*
import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeParameterMarker
@@ -442,7 +448,55 @@ class FirSignatureEnhancement(
AnnotationQualifierApplicabilityType.TYPE_PARAMETER_BOUNDS, contextQualifiers
).enhance(bound, emptyList(), FirJavaTypeConversionMode.TYPE_PARAMETER_BOUND_AFTER_FIRST_ROUND)
fun enhanceSuperType(type: FirTypeRef): FirTypeRef =
fun enhanceSuperTypes(unenhnancedSuperTypes: List<FirTypeRef>): List<FirTypeRef> {
val purelyImplementedSupertype = getPurelyImplementedSupertype(moduleData.session)
val purelyImplementedSupertypeClassId = purelyImplementedSupertype?.classId
return buildList {
unenhnancedSuperTypes.mapNotNullTo(this) { superType ->
enhanceSuperType(superType).takeUnless {
purelyImplementedSupertypeClassId != null && it.coneType.classId == purelyImplementedSupertypeClassId
}
}
purelyImplementedSupertype?.let {
add(buildResolvedTypeRef { type = it })
}
}
}
private fun getPurelyImplementedSupertype(session: FirSession): ConeKotlinType? {
val purelyImplementedClassIdFromAnnotation = owner.annotations
.firstOrNull { it.classId?.asSingleFqName() == JvmAnnotationNames.PURELY_IMPLEMENTS_ANNOTATION }
?.let { (it.argumentMapping.mapping.values.firstOrNull() as? FirConstExpression<*>) }
?.let { it.value as? String }
?.takeIf { it.isNotBlank() && isValidJavaFqName(it) }
?.let { ClassId.topLevel(FqName(it)) }
val purelyImplementedClassId = purelyImplementedClassIdFromAnnotation
?: FakePureImplementationsProvider.getPurelyImplementedInterface(owner.symbol.classId)
?: return null
val superTypeSymbol = session.symbolProvider.getClassLikeSymbolByClassId(purelyImplementedClassId) ?: return null
val superTypeParameterSymbols = superTypeSymbol.typeParameterSymbols ?: return null
val typeParameters = owner.typeParameters
val supertypeParameterCount = superTypeParameterSymbols.size
val typeParameterCount = typeParameters.size
val parametersAsTypeProjections = when {
typeParameterCount == supertypeParameterCount ->
typeParameters.map { ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(it.symbol), isNullable = false) }
typeParameterCount == 1 && supertypeParameterCount > 1 && purelyImplementedClassIdFromAnnotation == null -> {
val projection = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(typeParameters.first().symbol), isNullable = false)
(1..supertypeParameterCount).map { projection }
}
else -> return null
}
return ConeClassLikeTypeImpl(
ConeClassLikeLookupTagImpl(purelyImplementedClassId),
parametersAsTypeProjections.toTypedArray(),
isNullable = false
)
}
private fun enhanceSuperType(type: FirTypeRef): FirTypeRef =
EnhancementSignatureParts(
session, typeQualifierResolver, null, isCovariant = false, forceOnlyHeadTypeConstructor = false,
AnnotationQualifierApplicabilityType.TYPE_USE, contextQualifiers