diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompileTimeConstantProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompileTimeConstantProvider.kt index 6ca535c757f..95e426c02d2 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompileTimeConstantProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompileTimeConstantProvider.kt @@ -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 - } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirAnnotationValueConverter.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirAnnotationValueConverter.kt index 24ca661b679..8eb9fd48f1d 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirAnnotationValueConverter.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirAnnotationValueConverter.kt @@ -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() } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirCompileTimeConstantEvaluator.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirCompileTimeConstantEvaluator.kt index 9a96f620d1c..134bea1bdfc 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirCompileTimeConstantEvaluator.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/evaluate/FirCompileTimeConstantEvaluator.kt @@ -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) } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/renderer/FirAnnotationsIdeRenderer.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/renderer/FirAnnotationsIdeRenderer.kt index 4a3b8f7f075..32c12ebbffa 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/renderer/FirAnnotationsIdeRenderer.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/renderer/FirAnnotationsIdeRenderer.kt @@ -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 diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/firUtils.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/firUtils.kt index aacf250415b..c2c692266e1 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/firUtils.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/utils/firUtils.kt @@ -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) } diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constant/propertyInit_DivByOtherProperty_const.descriptors.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constant/propertyInit_DivByOtherProperty_const.descriptors.txt deleted file mode 100644 index 67e5f61e253..00000000000 --- a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constant/propertyInit_DivByOtherProperty_const.descriptors.txt +++ /dev/null @@ -1,3 +0,0 @@ -expression: 42 / d -constant: 42 -constantValueKind: Int diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constant/propertyInit_DivByOtherProperty_const.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constant/propertyInit_DivByOtherProperty_const.txt index 0b934314e80..67e5f61e253 100644 --- a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constant/propertyInit_DivByOtherProperty_const.txt +++ b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constant/propertyInit_DivByOtherProperty_const.txt @@ -1,3 +1,3 @@ expression: 42 / d -constant: NOT_EVALUATED -constantValueKind: NOT_EVALUATED +constant: 42 +constantValueKind: Int diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_const.descriptors.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_const.descriptors.txt deleted file mode 100644 index 67e5f61e253..00000000000 --- a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_const.descriptors.txt +++ /dev/null @@ -1,3 +0,0 @@ -expression: 42 / d -constant: 42 -constantValueKind: Int diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_const.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_const.txt index 0b934314e80..67e5f61e253 100644 --- a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_const.txt +++ b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_const.txt @@ -1,3 +1,3 @@ expression: 42 / d -constant: NOT_EVALUATED -constantValueKind: NOT_EVALUATED +constant: 42 +constantValueKind: Int diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_val.descriptors.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_val.descriptors.txt deleted file mode 100644 index 67e5f61e253..00000000000 --- a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_val.descriptors.txt +++ /dev/null @@ -1,3 +0,0 @@ -expression: 42 / d -constant: 42 -constantValueKind: Int diff --git a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_val.txt b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_val.txt index 0b934314e80..67e5f61e253 100644 --- a/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_val.txt +++ b/analysis/analysis-api/testData/components/compileTimeConstantProvider/evaluate_constantLike/propertyInit_DivByOtherProperty_val.txt @@ -1,3 +1,3 @@ expression: 42 / d -constant: NOT_EVALUATED -constantValueKind: NOT_EVALUATED +constant: 42 +constantValueKind: Int