AA: move logic to evaluate constant property initializer
so as to handle composite expressions w/ constant property
This commit is contained in:
committed by
Ilya Kirillov
parent
606033e1e6
commit
a7fcbfb717
+4
-32
@@ -15,16 +15,10 @@ 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.throwUnexpectedFirElementError
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isConst
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenBranch
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
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.psi.KtExpression
|
||||
|
||||
internal class KtFirCompileTimeConstantProvider(
|
||||
@@ -45,22 +39,15 @@ internal class KtFirCompileTimeConstantProvider(
|
||||
mode: KtConstantEvaluationMode,
|
||||
): KtConstantValue? = withValidityAssertion {
|
||||
when (fir) {
|
||||
is FirPropertyAccessExpression -> {
|
||||
fir.referredPropertySymbol?.toKtConstantValue(context, mode)
|
||||
}
|
||||
is FirExpression -> {
|
||||
is FirPropertyAccessExpression,
|
||||
is FirExpression,
|
||||
is FirNamedReference -> {
|
||||
try {
|
||||
FirCompileTimeConstantEvaluator.evaluateAsKtConstantExpression(fir)
|
||||
FirCompileTimeConstantEvaluator.evaluateAsKtConstantValue(fir, mode)
|
||||
} catch (e: ArithmeticException) {
|
||||
KtConstantValue.KtErrorConstantValue(e.localizedMessage, context)
|
||||
}
|
||||
}
|
||||
is FirNamedReference -> {
|
||||
when (val resolvedSymbol = fir.resolvedSymbol) {
|
||||
is FirPropertySymbol -> resolvedSymbol.toKtConstantValue(context, mode)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
// For invalid code like the following,
|
||||
// ```
|
||||
// when {
|
||||
@@ -73,19 +60,4 @@ internal class KtFirCompileTimeConstantProvider(
|
||||
else -> throwUnexpectedFirElementError(fir, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirPropertySymbol.toKtConstantValue(
|
||||
context: KtExpression,
|
||||
mode: KtConstantEvaluationMode,
|
||||
): KtConstantValue? = withValidityAssertion {
|
||||
if (isVal && hasInitializer) {
|
||||
if (mode == KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION && !isConst) {
|
||||
null
|
||||
} else {
|
||||
// NB: the initializer could be [FirLazyExpression] in [BodyBuildingMode.LAZY_BODIES].
|
||||
this.ensureResolved(FirResolvePhase.BODY_RESOLVE) // to unwrap lazy body
|
||||
evaluateFir(fir.initializer, context, mode)
|
||||
}
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.api.fir.evaluate
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.*
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValueFactory
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtConstantEvaluationMode
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
@@ -145,6 +146,7 @@ internal object FirAnnotationValueConverter {
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
} ?: FirCompileTimeConstantEvaluator.evaluate(this)?.convertConstantExpression()
|
||||
} ?: FirCompileTimeConstantEvaluator.evaluate(this, KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION)
|
||||
?.convertConstantExpression()
|
||||
}
|
||||
}
|
||||
|
||||
+56
-17
@@ -8,16 +8,22 @@ package org.jetbrains.kotlin.analysis.api.fir.evaluate
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValueFactory
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtConstantEvaluationMode
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.argument
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isConst
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolvedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.*
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
@@ -31,16 +37,49 @@ import org.jetbrains.kotlin.types.ConstantValueKind
|
||||
* and the argument, are compile-time constant as well.
|
||||
*/
|
||||
internal object FirCompileTimeConstantEvaluator {
|
||||
// TODO: Handle boolean operators, const property loading, class reference, array, annotation values, etc.
|
||||
fun evaluate(expression: FirExpression): FirConstExpression<*>? =
|
||||
when (expression) {
|
||||
is FirConstExpression<*> -> expression.adaptToConstKind()
|
||||
is FirFunctionCall -> evaluate(expression)
|
||||
// TODO: Handle boolean operators, class reference, array, annotation values, etc.
|
||||
fun evaluate(
|
||||
fir: FirElement?,
|
||||
mode: KtConstantEvaluationMode,
|
||||
): FirConstExpression<*>? =
|
||||
when (fir) {
|
||||
is FirPropertyAccessExpression -> {
|
||||
fir.referredPropertySymbol?.toConstExpression(mode)
|
||||
}
|
||||
is FirConstExpression<*> -> {
|
||||
fir.adaptToConstKind()
|
||||
}
|
||||
is FirFunctionCall -> {
|
||||
evaluateFunctionCall(fir, mode)
|
||||
}
|
||||
is FirNamedReference -> {
|
||||
when (val resolvedSymbol = fir.resolvedSymbol) {
|
||||
is FirPropertySymbol -> resolvedSymbol.toConstExpression(mode)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun evaluateAsKtConstantExpression(expression: FirExpression): KtConstantValue? {
|
||||
val evaluated = evaluate(expression) ?: return null
|
||||
private fun FirPropertySymbol.toConstExpression(
|
||||
mode: KtConstantEvaluationMode,
|
||||
): FirConstExpression<*>? {
|
||||
return when {
|
||||
mode == KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION && !isConst -> null
|
||||
isVal && hasInitializer -> {
|
||||
// NB: the initializer could be [FirLazyExpression] in [BodyBuildingMode.LAZY_BODIES].
|
||||
this.ensureResolved(FirResolvePhase.BODY_RESOLVE) // to unwrap lazy body
|
||||
evaluate(fir.initializer, mode)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun evaluateAsKtConstantValue(
|
||||
fir: FirElement,
|
||||
mode: KtConstantEvaluationMode,
|
||||
): KtConstantValue? {
|
||||
val evaluated = evaluate(fir, mode) ?: return null
|
||||
|
||||
val ktConstantValue = KtConstantValueFactory.createConstantValue(evaluated.value, evaluated.psi as? KtElement) ?: return null
|
||||
check(ktConstantValue.constantValueKind == evaluated.kind) {
|
||||
@@ -56,18 +95,18 @@ internal object FirCompileTimeConstantEvaluator {
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Rework to handle nested expressions
|
||||
// This is no longer used during FIR2IR where an inner expression is recursively rewritten to ConstExpression if possible.
|
||||
// Maybe rewrite this to a recursive version with caching either here or in provider.
|
||||
private fun evaluate(functionCall: FirFunctionCall): FirConstExpression<*>? {
|
||||
private fun evaluateFunctionCall(
|
||||
functionCall: FirFunctionCall,
|
||||
mode: KtConstantEvaluationMode,
|
||||
): FirConstExpression<*>? {
|
||||
val function = functionCall.getOriginalFunction() as? FirSimpleFunction ?: return null
|
||||
|
||||
val opr1 = functionCall.explicitReceiver as? FirConstExpression<*> ?: return null
|
||||
val opr1 = evaluate(functionCall.explicitReceiver, mode) ?: return null
|
||||
opr1.evaluate(function)?.let {
|
||||
return it.adjustType(functionCall.typeRef)
|
||||
}
|
||||
|
||||
val opr2 = functionCall.argument as? FirConstExpression<*> ?: return null
|
||||
val opr2 = evaluate(functionCall.argument, mode) ?: return null
|
||||
opr1.evaluate(function, opr2)?.let {
|
||||
return it.adjustType(functionCall.typeRef)
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirCompileTimeConstantEval
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtUnsupportedAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.renderAsSourceCode
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtConstantEvaluationMode
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
||||
@@ -60,7 +61,7 @@ private fun renderAndSortAnnotationArguments(descriptor: FirAnnotation, session:
|
||||
}
|
||||
|
||||
private fun renderConstant(value: FirExpression, useSiteSession: FirSession): String {
|
||||
val evaluated = FirCompileTimeConstantEvaluator.evaluate(value)
|
||||
val evaluated = FirCompileTimeConstantEvaluator.evaluate(value, KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION)
|
||||
val constantValue = FirAnnotationValueConverter.toConstantValue(evaluated ?: value, useSiteSession)
|
||||
?: KtUnsupportedAnnotationValue
|
||||
|
||||
|
||||
+4
-2
@@ -8,6 +8,7 @@ import com.intellij.psi.PsiElement
|
||||
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.components.KtConstantEvaluationMode
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirCompileTimeConstantEvaluator
|
||||
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
|
||||
@@ -28,7 +29,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.ConeNullability
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
@@ -91,7 +91,9 @@ internal fun FirCallableSymbol<*>.computeImportableName(useSiteSession: FirSessi
|
||||
|
||||
internal fun FirExpression.asKtInitializerValue(): KtInitializerValue {
|
||||
val ktExpression = psi as? KtExpression
|
||||
return when (val evaluated = FirCompileTimeConstantEvaluator.evaluateAsKtConstantExpression(this)) {
|
||||
val evaluated =
|
||||
FirCompileTimeConstantEvaluator.evaluateAsKtConstantValue(this, KtConstantEvaluationMode.CONSTANT_EXPRESSION_EVALUATION)
|
||||
return when (evaluated) {
|
||||
null -> KtNonConstantInitializerValue(ktExpression)
|
||||
else -> KtConstantInitializerValue(evaluated, ktExpression)
|
||||
}
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
expression: 42 / d
|
||||
constant: 42
|
||||
constantValueKind: Int
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
expression: 42 / d
|
||||
constant: NOT_EVALUATED
|
||||
constantValueKind: NOT_EVALUATED
|
||||
constant: 42
|
||||
constantValueKind: Int
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
expression: 42 / d
|
||||
constant: 42
|
||||
constantValueKind: Int
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
expression: 42 / d
|
||||
constant: NOT_EVALUATED
|
||||
constantValueKind: NOT_EVALUATED
|
||||
constant: 42
|
||||
constantValueKind: Int
|
||||
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
expression: 42 / d
|
||||
constant: 42
|
||||
constantValueKind: Int
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
expression: 42 / d
|
||||
constant: NOT_EVALUATED
|
||||
constantValueKind: NOT_EVALUATED
|
||||
constant: 42
|
||||
constantValueKind: Int
|
||||
|
||||
Reference in New Issue
Block a user