AA: avoid conversions to KtInitializerValue in constant evaluator

This commit is contained in:
Jinseong Jeon
2022-03-02 14:56:52 -08:00
committed by Ilya Kirillov
parent 1f93630a9c
commit ee23a52e54
@@ -5,27 +5,24 @@
package org.jetbrains.kotlin.analysis.api.fir.components package org.jetbrains.kotlin.analysis.api.fir.components
import org.jetbrains.kotlin.analysis.api.KtConstantInitializerValue
import org.jetbrains.kotlin.analysis.api.KtInitializerValue
import org.jetbrains.kotlin.analysis.api.KtNonConstantInitializerValue
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
import org.jetbrains.kotlin.analysis.api.components.KtCompileTimeConstantProvider import org.jetbrains.kotlin.analysis.api.components.KtCompileTimeConstantProvider
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirCompileTimeConstantEvaluator import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirCompileTimeConstantEvaluator
import org.jetbrains.kotlin.analysis.api.fir.symbols.getKtConstantInitializer
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.withValidityAssertion import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirWhenBranch import org.jetbrains.kotlin.fir.expressions.FirWhenBranch
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.resolvedSymbol import org.jetbrains.kotlin.fir.resolvedSymbol
import org.jetbrains.kotlin.fir.symbols.ensureResolved
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
internal class KtFirCompileTimeConstantProvider( internal class KtFirCompileTimeConstantProvider(
@@ -34,20 +31,24 @@ internal class KtFirCompileTimeConstantProvider(
) : KtCompileTimeConstantProvider(), KtFirAnalysisSessionComponent { ) : KtCompileTimeConstantProvider(), KtFirAnalysisSessionComponent {
override fun evaluate(expression: KtExpression): KtConstantValue? = withValidityAssertion { override fun evaluate(expression: KtExpression): KtConstantValue? = withValidityAssertion {
when (val fir = expression.getOrBuildFir(firResolveState)) { evaluateFir(expression.getOrBuildFir(firResolveState), expression)
}
private fun evaluateFir(fir: FirElement?, context: KtExpression): KtConstantValue? = withValidityAssertion {
when (fir) {
is FirPropertyAccessExpression -> { is FirPropertyAccessExpression -> {
fir.referredPropertySymbol?.toKtConstantValue() fir.referredPropertySymbol?.toKtConstantValue(context)
} }
is FirExpression -> { is FirExpression -> {
try { try {
FirCompileTimeConstantEvaluator.evaluateAsKtConstantExpression(fir) FirCompileTimeConstantEvaluator.evaluateAsKtConstantExpression(fir)
} catch (e: ArithmeticException) { } catch (e: ArithmeticException) {
KtConstantValue.KtErrorConstantValue(e.localizedMessage, fir.psi as? KtElement) KtConstantValue.KtErrorConstantValue(e.localizedMessage, context)
} }
} }
is FirNamedReference -> { is FirNamedReference -> {
when (val resolvedSymbol = fir.resolvedSymbol) { when (val resolvedSymbol = fir.resolvedSymbol) {
is FirPropertySymbol -> resolvedSymbol.toKtConstantValue() is FirPropertySymbol -> resolvedSymbol.toKtConstantValue(context)
else -> null else -> null
} }
} }
@@ -60,21 +61,15 @@ internal class KtFirCompileTimeConstantProvider(
// `false` does not have a corresponding elements on the FIR side and hence the containing `FirWhenBranch` is returned. In this // `false` does not have a corresponding elements on the FIR side and hence the containing `FirWhenBranch` is returned. In this
// case, we simply report null since FIR does not know about it. // case, we simply report null since FIR does not know about it.
is FirWhenBranch -> null is FirWhenBranch -> null
else -> throwUnexpectedFirElementError(fir, expression) else -> throwUnexpectedFirElementError(fir, context)
} }
} }
private fun FirPropertySymbol.toKtConstantValue(): KtConstantValue? = withValidityAssertion { private fun FirPropertySymbol.toKtConstantValue(context: KtExpression): KtConstantValue? = withValidityAssertion {
if (isVal) { if (isVal && hasInitializer) {
getKtConstantInitializer()?.toKtConstantValue() // NB: the initializer could be [FirLazyExpression] in [BodyBuildingMode.LAZY_BODIES].
this.ensureResolved(FirResolvePhase.BODY_RESOLVE) // to unwrap lazy body
evaluateFir(fir.initializer, context)
} else null } else null
} }
private fun KtInitializerValue?.toKtConstantValue(): KtConstantValue? = withValidityAssertion {
when (this) {
null -> null
is KtConstantInitializerValue -> constant
is KtNonConstantInitializerValue -> initializerPsi?.let { evaluate(it) }
}
}
} }