From ae68f088567ec1758c3e56f0e1f34a7af45361ee Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Tue, 27 Dec 2022 17:15:28 +0100 Subject: [PATCH] [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 --- .idea/dictionaries/darthorimar.xml | 7 +++ .../kotlin/fir/java/FirJavaFacade.kt | 56 +---------------- .../fir/java/declarations/FirJavaClass.kt | 14 +++-- .../java/enhancement/SignatureEnhancement.kt | 62 +++++++++++++++++-- .../tests/platformTypes/rawTypes/kt47459.kt | 1 - .../smartCastToClassWithRawSupertype.kt | 1 - 6 files changed, 77 insertions(+), 64 deletions(-) create mode 100644 .idea/dictionaries/darthorimar.xml diff --git a/.idea/dictionaries/darthorimar.xml b/.idea/dictionaries/darthorimar.xml new file mode 100644 index 00000000000..1cfd3d9dc18 --- /dev/null +++ b/.idea/dictionaries/darthorimar.xml @@ -0,0 +1,7 @@ + + + + unenhnanced + + + \ No newline at end of file diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt index b1f0262400a..c25a63b21b1 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt @@ -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, diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt index ca3cfb80a50..baa08cad75e 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt @@ -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, override val scopeProvider: FirScopeProvider, override val symbol: FirRegularClassSymbol, - override val superTypeRefs: MutableList, + private val unenhnancedSuperTypes: List, override val typeParameters: MutableList, 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 by lazy { + val enhancement = FirSignatureEnhancement(this@FirJavaClass, moduleData.session, overridden = { emptyList() }) + enhancement.enhanceSuperTypes(unenhnancedSuperTypes) + } + override fun replaceSuperTypeRefs(newSuperTypeRefs: List) { - 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 transformSuperTypeRefs(transformer: FirTransformer, 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, diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt index b28ad301a82..15485022a67 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/SignatureEnhancement.kt @@ -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): List { + 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 diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/kt47459.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/kt47459.kt index 0b2ce152d44..f31435a13b7 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/kt47459.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/kt47459.kt @@ -1,4 +1,3 @@ -// FIR_DISABLE_LAZY_RESOLVE_CHECKS // FIR_IDENTICAL // FILE: MapObjectManager.java abstract class MapObjectManager { diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/smartCastToClassWithRawSupertype.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/smartCastToClassWithRawSupertype.kt index 2afe731f1c8..b5f72f96377 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/smartCastToClassWithRawSupertype.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/smartCastToClassWithRawSupertype.kt @@ -1,4 +1,3 @@ -// FIR_DISABLE_LAZY_RESOLVE_CHECKS // FIR_IDENTICAL // SKIP_TXT // !DIAGNOSTICS: -UNUSED_VARIABLE