[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.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)
|
||||
|
||||
+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")))
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user