[FIR] Improve performance of missing supertype detection
^KT-62619 Fixed
This commit is contained in:
+19
-41
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.KtSourceElement
|
|||||||
import org.jetbrains.kotlin.config.AnalysisFlags
|
import org.jetbrains.kotlin.config.AnalysisFlags
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.collectUpperBounds
|
import org.jetbrains.kotlin.fir.analysis.checkers.collectUpperBounds
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
|
||||||
@@ -36,13 +35,13 @@ object FirMissingDependencySupertypeChecker {
|
|||||||
object ForDeclarations : FirBasicDeclarationChecker() {
|
object ForDeclarations : FirBasicDeclarationChecker() {
|
||||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (declaration is FirClass) {
|
if (declaration is FirClass) {
|
||||||
checkSupertypes(declaration.symbol, declaration.source, reporter, context)
|
checkSuperTypes(declaration.symbol, declaration.source, reporter, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (declaration is FirTypeParameterRefsOwner) {
|
if (declaration is FirTypeParameterRefsOwner) {
|
||||||
for (typeParameter in declaration.typeParameters) {
|
for (typeParameter in declaration.typeParameters) {
|
||||||
for (upperBound in typeParameter.toConeType().collectUpperBounds()) {
|
for (upperBound in typeParameter.toConeType().collectUpperBounds()) {
|
||||||
checkSupertypes(upperBound, typeParameter.source, reporter, context)
|
checkSuperTypes(upperBound, typeParameter.source, reporter, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,30 +56,30 @@ object FirMissingDependencySupertypeChecker {
|
|||||||
if (symbol == null) {
|
if (symbol == null) {
|
||||||
val receiverType = expression.explicitReceiver?.resolvedType
|
val receiverType = expression.explicitReceiver?.resolvedType
|
||||||
?.lowerBoundIfFlexible()?.originalIfDefinitelyNotNullable()?.fullyExpandedType(context.session)
|
?.lowerBoundIfFlexible()?.originalIfDefinitelyNotNullable()?.fullyExpandedType(context.session)
|
||||||
checkSupertypes(receiverType, source, reporter, context)
|
checkSuperTypes(receiverType, source, reporter, context)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val missingSupertype = checkSupertypes(symbol.dispatchReceiverType, source, reporter, context)
|
val missingSupertype = checkSuperTypes(symbol.dispatchReceiverType, source, reporter, context)
|
||||||
|
|
||||||
val eagerChecksAllowed = context.languageVersionSettings.getFlag(AnalysisFlags.extendedCompilerChecks)
|
val eagerChecksAllowed = context.languageVersionSettings.getFlag(AnalysisFlags.extendedCompilerChecks)
|
||||||
val unresolvedLazySupertypesByDefault = symbol is FirConstructorSymbol || symbol is FirAnonymousFunctionSymbol
|
val unresolvedLazySupertypesByDefault = symbol is FirConstructorSymbol || symbol is FirAnonymousFunctionSymbol
|
||||||
|
|
||||||
if (eagerChecksAllowed || !unresolvedLazySupertypesByDefault && !missingSupertype) {
|
if (eagerChecksAllowed || !unresolvedLazySupertypesByDefault && !missingSupertype) {
|
||||||
checkSupertypes(symbol.getOwnerLookupTag()?.toSymbol(context.session), source, reporter, context)
|
checkSuperTypes(symbol.getOwnerLookupTag()?.toSymbol(context.session), source, reporter, context)
|
||||||
checkSupertypes(symbol.resolvedReceiverTypeRef?.coneTypeOrNull, source, reporter, context)
|
checkSuperTypes(symbol.resolvedReceiverTypeRef?.coneTypeOrNull, source, reporter, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkSupertypes(
|
fun checkSuperTypes(
|
||||||
classifierType: ConeKotlinType?,
|
classifierType: ConeKotlinType?,
|
||||||
source: KtSourceElement?,
|
source: KtSourceElement?,
|
||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
): Boolean = checkSupertypes(classifierType?.toSymbol(context.session), source, reporter, context)
|
): Boolean = checkSuperTypes(classifierType?.toSymbol(context.session), source, reporter, context)
|
||||||
|
|
||||||
fun checkSupertypes(
|
fun checkSuperTypes(
|
||||||
declaration: FirBasedSymbol<*>?,
|
declaration: FirBasedSymbol<*>?,
|
||||||
source: KtSourceElement?,
|
source: KtSourceElement?,
|
||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
@@ -88,38 +87,17 @@ object FirMissingDependencySupertypeChecker {
|
|||||||
): Boolean {
|
): Boolean {
|
||||||
if (declaration !is FirClassSymbol<*>) return false
|
if (declaration !is FirClassSymbol<*>) return false
|
||||||
|
|
||||||
var missingSupertype = false
|
val missingSuperTypes = context.session.missingDependencyStorage.getMissingSuperTypes(declaration)
|
||||||
val superTypes = declaration.collectSuperTypes(context.session)
|
for (superType in missingSuperTypes) {
|
||||||
for (superType in superTypes) {
|
reporter.reportOn(
|
||||||
if (superType is ConeErrorType || superType is ConeDynamicType) continue // Ignore types which are already errors.
|
source,
|
||||||
|
FirErrors.MISSING_DEPENDENCY_SUPERCLASS,
|
||||||
val superTypeSymbol = superType.toSymbol(context.session)
|
superType.withArguments(emptyArray()).withNullability(ConeNullability.NOT_NULL, context.session.typeContext),
|
||||||
if (superTypeSymbol == null) {
|
declaration.constructType(emptyArray(), false),
|
||||||
missingSupertype = true
|
context
|
||||||
|
)
|
||||||
reporter.reportOn(
|
|
||||||
source,
|
|
||||||
FirErrors.MISSING_DEPENDENCY_SUPERCLASS,
|
|
||||||
superType.withArguments(emptyArray()).withNullability(ConeNullability.NOT_NULL, context.session.typeContext),
|
|
||||||
declaration.constructType(emptyArray(), false),
|
|
||||||
context
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return missingSupertype
|
return missingSuperTypes.isNotEmpty()
|
||||||
}
|
|
||||||
|
|
||||||
private fun FirClassSymbol<*>.collectSuperTypes(session: FirSession): Set<ConeKotlinType> {
|
|
||||||
val superTypes = mutableSetOf<ConeKotlinType>()
|
|
||||||
fun collect(symbol: FirClassSymbol<*>) {
|
|
||||||
for (superType in symbol.resolvedSuperTypes) {
|
|
||||||
if (superTypes.add(superType)) {
|
|
||||||
(superType.toSymbol(session) as? FirClassSymbol<*>)?.let(::collect)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
collect(this)
|
|
||||||
return superTypes
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion
|
|||||||
register(FirAnnotationsPlatformSpecificSupportComponent::class, FirAnnotationsPlatformSpecificSupportComponent.Default)
|
register(FirAnnotationsPlatformSpecificSupportComponent::class, FirAnnotationsPlatformSpecificSupportComponent.Default)
|
||||||
register(FirPrimaryConstructorSuperTypeCheckerPlatformComponent::class, FirPrimaryConstructorSuperTypeCheckerPlatformComponent.Default)
|
register(FirPrimaryConstructorSuperTypeCheckerPlatformComponent::class, FirPrimaryConstructorSuperTypeCheckerPlatformComponent.Default)
|
||||||
register(FirGenericArrayClassLiteralSupport::class, FirGenericArrayClassLiteralSupport.Disabled)
|
register(FirGenericArrayClassLiteralSupport::class, FirGenericArrayClassLiteralSupport.Disabled)
|
||||||
|
register(FirMissingDependencyStorage::class, FirMissingDependencyStorage(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(SessionConfiguration::class)
|
@OptIn(SessionConfiguration::class)
|
||||||
|
|||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.types
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.FirSessionComponent
|
||||||
|
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
|
||||||
|
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||||
|
|
||||||
|
@ThreadSafeMutableState
|
||||||
|
class FirMissingDependencyStorage(private val session: FirSession) : FirSessionComponent {
|
||||||
|
private val cache =
|
||||||
|
session.firCachesFactory.createCache<FirClassSymbol<*>, Set<ConeKotlinType>, Nothing?> { symbol, _ ->
|
||||||
|
findMissingSuperTypes(symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getMissingSuperTypes(declaration: FirClassSymbol<*>): Set<ConeKotlinType> {
|
||||||
|
return cache.getValue(declaration, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findMissingSuperTypes(declaration: FirClassSymbol<*>): Set<ConeKotlinType> {
|
||||||
|
return declaration.collectSuperTypes(session)
|
||||||
|
.filterTo(mutableSetOf()) {
|
||||||
|
// Ignore types which are already errors.
|
||||||
|
it !is ConeErrorType && it !is ConeDynamicType && it.toSymbol(session) == null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirClassSymbol<*>.collectSuperTypes(session: FirSession): Set<ConeKotlinType> {
|
||||||
|
val superTypes = mutableSetOf<ConeKotlinType>()
|
||||||
|
fun collect(symbol: FirClassSymbol<*>) {
|
||||||
|
for (superTypeRef in symbol.resolvedSuperTypeRefs) {
|
||||||
|
val superType = superTypeRef.type
|
||||||
|
if (!superType.isAny && superTypes.add(superType)) {
|
||||||
|
(superType.toSymbol(session) as? FirClassSymbol<*>)?.let(::collect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collect(this)
|
||||||
|
return superTypes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val FirSession.missingDependencyStorage: FirMissingDependencyStorage by FirSession.sessionComponentAccessor()
|
||||||
+1
-1
@@ -149,7 +149,7 @@ abstract class AbstractCompileKotlinAgainstCustomBinariesTest : AbstractKotlinCo
|
|||||||
compileKotlin("source.kt", tmpdir, listOf(compileLibrary("library-1"), compileLibrary("library-2")))
|
compileKotlin("source.kt", tmpdir, listOf(compileLibrary("library-1"), compileLibrary("library-2")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// KT-60778 K2: implement MISSING_DEPENDENCY_CLASS(_SUPERCLASS) errors
|
// KT-62900 K2: Expected expression to be resolved during Fir2Ir
|
||||||
fun testMissingEnumReferencedInAnnotationArgument() = muteForK2 {
|
fun testMissingEnumReferencedInAnnotationArgument() = muteForK2 {
|
||||||
doTestBrokenLibrary("library", "a/E.class")
|
doTestBrokenLibrary("library", "a/E.class")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user