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.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.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.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.references.FirNamedReference
|
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
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
|
||||||
internal class KtFirCompileTimeConstantProvider(
|
internal class KtFirCompileTimeConstantProvider(
|
||||||
@@ -45,22 +39,15 @@ internal class KtFirCompileTimeConstantProvider(
|
|||||||
mode: KtConstantEvaluationMode,
|
mode: KtConstantEvaluationMode,
|
||||||
): KtConstantValue? = withValidityAssertion {
|
): KtConstantValue? = withValidityAssertion {
|
||||||
when (fir) {
|
when (fir) {
|
||||||
is FirPropertyAccessExpression -> {
|
is FirPropertyAccessExpression,
|
||||||
fir.referredPropertySymbol?.toKtConstantValue(context, mode)
|
is FirExpression,
|
||||||
}
|
is FirNamedReference -> {
|
||||||
is FirExpression -> {
|
|
||||||
try {
|
try {
|
||||||
FirCompileTimeConstantEvaluator.evaluateAsKtConstantExpression(fir)
|
FirCompileTimeConstantEvaluator.evaluateAsKtConstantValue(fir, mode)
|
||||||
} catch (e: ArithmeticException) {
|
} catch (e: ArithmeticException) {
|
||||||
KtConstantValue.KtErrorConstantValue(e.localizedMessage, context)
|
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,
|
// For invalid code like the following,
|
||||||
// ```
|
// ```
|
||||||
// when {
|
// when {
|
||||||
@@ -73,19 +60,4 @@ internal class KtFirCompileTimeConstantProvider(
|
|||||||
else -> throwUnexpectedFirElementError(fir, context)
|
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.annotations.*
|
||||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValueFactory
|
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.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||||
@@ -145,6 +146,7 @@ internal object FirAnnotationValueConverter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> null
|
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.KtSourceElement
|
||||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
import org.jetbrains.kotlin.analysis.api.base.KtConstantValue
|
||||||
import org.jetbrains.kotlin.analysis.api.base.KtConstantValueFactory
|
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.FirCallableDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
import org.jetbrains.kotlin.fir.declarations.utils.isConst
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.argument
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
|
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
|
||||||
import org.jetbrains.kotlin.fir.psi
|
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.references.FirResolvedNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolvedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
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.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.*
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
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.
|
* and the argument, are compile-time constant as well.
|
||||||
*/
|
*/
|
||||||
internal object FirCompileTimeConstantEvaluator {
|
internal object FirCompileTimeConstantEvaluator {
|
||||||
// TODO: Handle boolean operators, const property loading, class reference, array, annotation values, etc.
|
// TODO: Handle boolean operators, class reference, array, annotation values, etc.
|
||||||
fun evaluate(expression: FirExpression): FirConstExpression<*>? =
|
fun evaluate(
|
||||||
when (expression) {
|
fir: FirElement?,
|
||||||
is FirConstExpression<*> -> expression.adaptToConstKind()
|
mode: KtConstantEvaluationMode,
|
||||||
is FirFunctionCall -> evaluate(expression)
|
): 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
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun evaluateAsKtConstantExpression(expression: FirExpression): KtConstantValue? {
|
private fun FirPropertySymbol.toConstExpression(
|
||||||
val evaluated = evaluate(expression) ?: return null
|
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
|
val ktConstantValue = KtConstantValueFactory.createConstantValue(evaluated.value, evaluated.psi as? KtElement) ?: return null
|
||||||
check(ktConstantValue.constantValueKind == evaluated.kind) {
|
check(ktConstantValue.constantValueKind == evaluated.kind) {
|
||||||
@@ -56,18 +95,18 @@ internal object FirCompileTimeConstantEvaluator {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Rework to handle nested expressions
|
private fun evaluateFunctionCall(
|
||||||
// This is no longer used during FIR2IR where an inner expression is recursively rewritten to ConstExpression if possible.
|
functionCall: FirFunctionCall,
|
||||||
// Maybe rewrite this to a recursive version with caching either here or in provider.
|
mode: KtConstantEvaluationMode,
|
||||||
private fun evaluate(functionCall: FirFunctionCall): FirConstExpression<*>? {
|
): FirConstExpression<*>? {
|
||||||
val function = functionCall.getOriginalFunction() as? FirSimpleFunction ?: return null
|
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 {
|
opr1.evaluate(function)?.let {
|
||||||
return it.adjustType(functionCall.typeRef)
|
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 {
|
opr1.evaluate(function, opr2)?.let {
|
||||||
return it.adjustType(functionCall.typeRef)
|
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.fir.evaluate.FirAnnotationValueConverter
|
||||||
import org.jetbrains.kotlin.analysis.api.annotations.KtUnsupportedAnnotationValue
|
import org.jetbrains.kotlin.analysis.api.annotations.KtUnsupportedAnnotationValue
|
||||||
import org.jetbrains.kotlin.analysis.api.annotations.renderAsSourceCode
|
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.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
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 {
|
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)
|
val constantValue = FirAnnotationValueConverter.toConstantValue(evaluated ?: value, useSiteSession)
|
||||||
?: KtUnsupportedAnnotationValue
|
?: 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.KtConstantInitializerValue
|
||||||
import org.jetbrains.kotlin.analysis.api.KtInitializerValue
|
import org.jetbrains.kotlin.analysis.api.KtInitializerValue
|
||||||
import org.jetbrains.kotlin.analysis.api.KtNonConstantInitializerValue
|
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.evaluate.FirCompileTimeConstantEvaluator
|
||||||
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
|
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
|
||||||
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
|
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.ConeErrorType
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.ConeNullability
|
import org.jetbrains.kotlin.fir.types.ConeNullability
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
|
||||||
@@ -91,7 +91,9 @@ internal fun FirCallableSymbol<*>.computeImportableName(useSiteSession: FirSessi
|
|||||||
|
|
||||||
internal fun FirExpression.asKtInitializerValue(): KtInitializerValue {
|
internal fun FirExpression.asKtInitializerValue(): KtInitializerValue {
|
||||||
val ktExpression = psi as? KtExpression
|
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)
|
null -> KtNonConstantInitializerValue(ktExpression)
|
||||||
else -> KtConstantInitializerValue(evaluated, 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
|
expression: 42 / d
|
||||||
constant: NOT_EVALUATED
|
constant: 42
|
||||||
constantValueKind: NOT_EVALUATED
|
constantValueKind: Int
|
||||||
|
|||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
expression: 42 / d
|
|
||||||
constant: 42
|
|
||||||
constantValueKind: Int
|
|
||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
expression: 42 / d
|
expression: 42 / d
|
||||||
constant: NOT_EVALUATED
|
constant: 42
|
||||||
constantValueKind: NOT_EVALUATED
|
constantValueKind: Int
|
||||||
|
|||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
expression: 42 / d
|
|
||||||
constant: 42
|
|
||||||
constantValueKind: Int
|
|
||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
expression: 42 / d
|
expression: 42 / d
|
||||||
constant: NOT_EVALUATED
|
constant: 42
|
||||||
constantValueKind: NOT_EVALUATED
|
constantValueKind: Int
|
||||||
|
|||||||
Reference in New Issue
Block a user