[FIR] Improve performance of missing supertype detection

^KT-62619 Fixed
This commit is contained in:
Brian Norman
2023-10-26 07:40:52 -05:00
committed by Space Team
parent c55dc2578a
commit 1bb5e97b62
4 changed files with 69 additions and 42 deletions
@@ -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)
@@ -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()
@@ -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")
} }