From 2463b904f74aa507e59e09cf07662edab99e9781 Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Thu, 6 Apr 2023 11:04:32 +0200 Subject: [PATCH] [LL FIR] add ability to suppress contract violation exception ^KT-56543 --- .../resolve/LLFirLazyResolveContractChecker.kt | 18 ++++++++++++------ .../fir/symbols/FirLazyDeclarationResolver.kt | 11 +++++++++++ ...LazyDeclarationResolverWithPhaseChecking.kt | 15 ++++++--------- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirLazyResolveContractChecker.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirLazyResolveContractChecker.kt index a66db546f46..bb1434fdd97 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirLazyResolveContractChecker.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/LLFirLazyResolveContractChecker.kt @@ -5,7 +5,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve +import com.intellij.openapi.diagnostic.Logger import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.symbols.FirLazyResolveContractViolationException internal class LLFirLazyResolveContractChecker { private val currentTransformerPhase = ThreadLocal.withInitial { null } @@ -26,12 +28,16 @@ internal class LLFirLazyResolveContractChecker { val currentPhase = currentTransformerPhase.get() ?: return if (requestedPhase >= currentPhase) { - error( - """`lazyResolveToPhase($requestedPhase)` cannot be called from a transformer with a phase $currentPhase. - `lazyResolveToPhase` can be called only from a transformer with a phase which is strictly greater than a requested phase; - i.e., `lazyResolveToPhase(A)` may be only called from a lazy transformer with a phase B, where A < B. This is a contract of lazy resolve""".trimIndent() - ) + val exception = FirLazyResolveContractViolationException(currentPhase = currentPhase, requestedPhase = requestedPhase) + if (System.getProperty("kotlin.suppress.lazy.resolve.contract.violation") != null) { + LoggerHolder.LOG.warn(exception) + } else { + throw exception + } } } -} + private object LoggerHolder { + val LOG = Logger.getInstance(LLFirLazyResolveContractChecker::class.java) + } +} 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 0de05d73558..c88aedda2b6 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 @@ -44,6 +44,17 @@ abstract class FirLazyDeclarationResolver : FirSessionComponent { abstract fun lazyResolveToPhaseWithCallableMembers(symbol: FirClassSymbol<*>, toPhase: FirResolvePhase) } +class FirLazyResolveContractViolationException( + currentPhase: FirResolvePhase, + requestedPhase: FirResolvePhase, +) : IllegalStateException( + """ + `lazyResolveToPhase($requestedPhase)` cannot be called from a transformer with a phase $currentPhase. + `lazyResolveToPhase` can be called only from a transformer with a phase which is strictly greater than a requested phase; + i.e., `lazyResolveToPhase(A)` may be only called from a lazy transformer with a phase B, where A < B. This is a contract of lazy resolve + """.trimIndent() +) + val FirSession.lazyDeclarationResolver: FirLazyDeclarationResolver by FirSession.sessionComponentAccessor() private val FirDeclaration.lazyDeclarationResolver get() = moduleData.session.lazyDeclarationResolver diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirCompilerLazyDeclarationResolverWithPhaseChecking.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirCompilerLazyDeclarationResolverWithPhaseChecking.kt index 05d81d5102c..ec4705b22b6 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirCompilerLazyDeclarationResolverWithPhaseChecking.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirCompilerLazyDeclarationResolverWithPhaseChecking.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test.frontend.fir.handlers import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver +import org.jetbrains.kotlin.fir.symbols.FirLazyResolveContractViolationException import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol @@ -20,11 +21,11 @@ class FirCompilerLazyDeclarationResolverWithPhaseChecking : FirLazyDeclarationRe exceptions override fun lazyResolveToPhase(symbol: FirBasedSymbol<*>, toPhase: FirResolvePhase) { - checkIfCanLazyResolveToPhase(symbol, toPhase) + checkIfCanLazyResolveToPhase(toPhase) } override fun lazyResolveToPhaseWithCallableMembers(symbol: FirClassSymbol<*>, toPhase: FirResolvePhase) { - checkIfCanLazyResolveToPhase(symbol, toPhase) + checkIfCanLazyResolveToPhase(toPhase) } override fun startResolvingPhase(phase: FirResolvePhase) { @@ -37,7 +38,7 @@ class FirCompilerLazyDeclarationResolverWithPhaseChecking : FirLazyDeclarationRe currentTransformerPhase = null } - private fun checkIfCanLazyResolveToPhase(symbol: FirBasedSymbol<*>, requestedPhase: FirResolvePhase) { + private fun checkIfCanLazyResolveToPhase(requestedPhase: FirResolvePhase) { if (!lazyResolveContractChecksEnabled) return val currentPhase = currentTransformerPhase @@ -50,13 +51,9 @@ class FirCompilerLazyDeclarationResolverWithPhaseChecking : FirLazyDeclarationRe // but due to usage of already resolved stdlib classes we don't see it if (requestedPhase >= currentPhase) { exceptions += FirLazyResolveContractViolationException( - """`lazyResolveToPhase($requestedPhase)` cannot be called from a transformer with a phase $currentPhase. - lazyResolveToPhase was called on a $symbol. - `lazyResolveToPhase` can be called only from a transformer with a phase which is strictly greater than a requested phase; - i.e., `lazyResolveToPhase(A)` may be only called from a lazy transformer with a phase B, where A < B. This is a contract of lazy resolve""".trimIndent() + currentPhase = currentPhase, + requestedPhase = requestedPhase, ) } } } - -class FirLazyResolveContractViolationException(message: String) : IllegalStateException(message)