[FIR] forbid resolve from `currentDeclarationDeprecationsAreDefinitelyEmpty`
as `currentDeclarationDeprecationsAreDefinitelyEmpty` should be a check for a fast path.
KT-70114
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirLazyDeclarationResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirLazyDeclarationResolver.kt
index 14b1ba6..5a2a4f2 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirLazyDeclarationResolver.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirLazyDeclarationResolver.kt
@@ -22,6 +22,7 @@
override fun finishResolvingPhase(phase: FirResolvePhase) {}
override fun lazyResolveToPhase(element: FirElementWithResolveState, toPhase: FirResolvePhase) {
+ assertLazyResolveAllowed()
val session = element.llFirResolvableSession ?: return
session.moduleComponents.firModuleLazyDeclarationResolver.lazyResolve(
target = element,
@@ -30,6 +31,7 @@
}
override fun lazyResolveToPhaseWithCallableMembers(clazz: FirClass, toPhase: FirResolvePhase) {
+ assertLazyResolveAllowed()
val fir = clazz as? FirRegularClass ?: return
val session = fir.llFirResolvableSession ?: return
session.moduleComponents.firModuleLazyDeclarationResolver.lazyResolveWithCallableMembers(
@@ -46,6 +48,7 @@
}
override fun lazyResolveToPhaseRecursively(element: FirElementWithResolveState, toPhase: FirResolvePhase) {
+ assertLazyResolveAllowed()
val session = element.llFirResolvableSession ?: return
session.moduleComponents.firModuleLazyDeclarationResolver.lazyResolveRecursively(
target = element,
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirLazyDeclarationResolver.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirLazyDeclarationResolver.kt
index 0c2bc69..68add2f 100644
--- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirLazyDeclarationResolver.kt
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirLazyDeclarationResolver.kt
@@ -31,6 +31,11 @@
val lazyResolveContractChecksEnabled: Boolean
get() = _lazyResolveContractChecksEnabled.get()
+
+ @PrivateForInline
+ @Suppress("PropertyName")
+ val _lazyResolveIsAllowed: ThreadLocal<Boolean> = ThreadLocal.withInitial { true }
+
abstract fun startResolvingPhase(phase: FirResolvePhase)
abstract fun finishResolvingPhase(phase: FirResolvePhase)
@@ -51,6 +56,24 @@
}
}
+ @OptIn(PrivateForInline::class)
+ inline fun <T> forbidLazyResolveInside(action: () -> T): T {
+ val current = _lazyResolveIsAllowed.get()
+ _lazyResolveIsAllowed.set(false)
+ try {
+ return action()
+ } finally {
+ _lazyResolveIsAllowed.set(current)
+ }
+ }
+
+ @OptIn(PrivateForInline::class)
+ protected fun assertLazyResolveAllowed() {
+ if (!_lazyResolveIsAllowed.get()) {
+ throw FirLazyResolveForbiddenException()
+ }
+ }
+
/**
* @see org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
*/
@@ -67,6 +90,8 @@
abstract fun lazyResolveToPhaseRecursively(element: FirElementWithResolveState, toPhase: FirResolvePhase)
}
+class FirLazyResolveForbiddenException() : IllegalStateException("Lazy resolve is forbidden")
+
class FirLazyResolveContractViolationException(
currentPhase: FirResolvePhase,
requestedPhase: FirResolvePhase,
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt
index 8ec25b5..f75e849 100644
--- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirCallableSymbol.kt
@@ -8,6 +8,7 @@
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
+import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.mpp.CallableSymbolMarker
@@ -114,15 +115,17 @@
* such as parent or child declarations.
*/
internal fun currentDeclarationDeprecationsAreDefinitelyEmpty(): Boolean {
- if (origin is FirDeclarationOrigin.Java) {
- // Java may perform lazy resolution when accessing FIR tree internals, see KT-55387
+ moduleData.session.lazyDeclarationResolver.forbidLazyResolveInside {
+ if (origin is FirDeclarationOrigin.Java) {
+ // Java may perform lazy resolution when accessing FIR tree internals, see KT-55387
+ return false
+ }
+ if (annotations.isEmpty() && fir.versionRequirements.isNullOrEmpty() && !rawStatus.isOverride) return true
+ if (fir.deprecationsProvider == EmptyDeprecationsProvider) {
+ return true
+ }
return false
}
- if (annotations.isEmpty() && fir.versionRequirements.isNullOrEmpty() && !rawStatus.isOverride) return true
- if (fir.deprecationsProvider == EmptyDeprecationsProvider) {
- return true
- }
- return false
}
private fun ensureType(typeRef: FirTypeRef?) {