[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.diagnostics.DiagnosticReporter
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.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
@@ -36,13 +35,13 @@ object FirMissingDependencySupertypeChecker {
object ForDeclarations : FirBasicDeclarationChecker() {
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
if (declaration is FirClass) {
checkSupertypes(declaration.symbol, declaration.source, reporter, context)
checkSuperTypes(declaration.symbol, declaration.source, reporter, context)
}
if (declaration is FirTypeParameterRefsOwner) {
for (typeParameter in declaration.typeParameters) {
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) {
val receiverType = expression.explicitReceiver?.resolvedType
?.lowerBoundIfFlexible()?.originalIfDefinitelyNotNullable()?.fullyExpandedType(context.session)
checkSupertypes(receiverType, source, reporter, context)
checkSuperTypes(receiverType, source, reporter, context)
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 unresolvedLazySupertypesByDefault = symbol is FirConstructorSymbol || symbol is FirAnonymousFunctionSymbol
if (eagerChecksAllowed || !unresolvedLazySupertypesByDefault && !missingSupertype) {
checkSupertypes(symbol.getOwnerLookupTag()?.toSymbol(context.session), source, reporter, context)
checkSupertypes(symbol.resolvedReceiverTypeRef?.coneTypeOrNull, source, reporter, context)
checkSuperTypes(symbol.getOwnerLookupTag()?.toSymbol(context.session), source, reporter, context)
checkSuperTypes(symbol.resolvedReceiverTypeRef?.coneTypeOrNull, source, reporter, context)
}
}
}
fun checkSupertypes(
fun checkSuperTypes(
classifierType: ConeKotlinType?,
source: KtSourceElement?,
reporter: DiagnosticReporter,
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<*>?,
source: KtSourceElement?,
reporter: DiagnosticReporter,
@@ -88,38 +87,17 @@ object FirMissingDependencySupertypeChecker {
): Boolean {
if (declaration !is FirClassSymbol<*>) return false
var missingSupertype = false
val superTypes = declaration.collectSuperTypes(context.session)
for (superType in superTypes) {
if (superType is ConeErrorType || superType is ConeDynamicType) continue // Ignore types which are already errors.
val superTypeSymbol = superType.toSymbol(context.session)
if (superTypeSymbol == null) {
missingSupertype = true
reporter.reportOn(
source,
FirErrors.MISSING_DEPENDENCY_SUPERCLASS,
superType.withArguments(emptyArray()).withNullability(ConeNullability.NOT_NULL, context.session.typeContext),
declaration.constructType(emptyArray(), false),
context
)
}
val missingSuperTypes = context.session.missingDependencyStorage.getMissingSuperTypes(declaration)
for (superType in missingSuperTypes) {
reporter.reportOn(
source,
FirErrors.MISSING_DEPENDENCY_SUPERCLASS,
superType.withArguments(emptyArray()).withNullability(ConeNullability.NOT_NULL, context.session.typeContext),
declaration.constructType(emptyArray(), false),
context
)
}
return missingSupertype
}
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
return missingSuperTypes.isNotEmpty()
}
}
@@ -92,6 +92,7 @@ fun FirSession.registerCommonComponents(languageVersionSettings: LanguageVersion
register(FirAnnotationsPlatformSpecificSupportComponent::class, FirAnnotationsPlatformSpecificSupportComponent.Default)
register(FirPrimaryConstructorSuperTypeCheckerPlatformComponent::class, FirPrimaryConstructorSuperTypeCheckerPlatformComponent.Default)
register(FirGenericArrayClassLiteralSupport::class, FirGenericArrayClassLiteralSupport.Disabled)
register(FirMissingDependencyStorage::class, FirMissingDependencyStorage(this))
}
@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")))
}
// KT-60778 K2: implement MISSING_DEPENDENCY_CLASS(_SUPERCLASS) errors
// KT-62900 K2: Expected expression to be resolved during Fir2Ir
fun testMissingEnumReferencedInAnnotationArgument() = muteForK2 {
doTestBrokenLibrary("library", "a/E.class")
}