From c3c79b874d2f8172392a328936d9d121b6fe0568 Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Thu, 28 Oct 2021 00:10:20 -0700 Subject: [PATCH] FIR IDE: make constant evaluator robust to arithmetic exception --- .../components/KtFe10CompileTimeConstantProvider.kt | 2 +- .../symbols/descriptorBased/base/Kt1DescUtils.kt | 3 ++- .../components/KtFirCompileTimeConstantProvider.kt | 8 ++++++-- .../fir/evaluate/FirCompileTimeConstantEvaluator.kt | 6 +++--- .../FirCompileTimeConstantEvaluatorTestGenerated.java | 6 ++++++ .../AbstractCompileTimeConstantEvaluatorTest.kt | 1 + .../analysis/api/symbols/markers/KtConstantValue.kt | 11 +++++++++++ .../propertyInit_DivByZero.kt | 1 + .../propertyInit_DivByZero.txt | 3 +++ .../kotlin/resolve/constants/constantValues.kt | 2 +- 10 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_DivByZero.kt create mode 100644 analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_DivByZero.txt diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CompileTimeConstantProvider.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CompileTimeConstantProvider.kt index 2e9cf50e96b..252402345a0 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CompileTimeConstantProvider.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CompileTimeConstantProvider.kt @@ -31,4 +31,4 @@ internal class KtFe10CompileTimeConstantProvider(override val analysisSession: K val bindingTrace = DelegatingBindingTrace(bindingContext, "Binding trace for constant expression evaluation") return evaluator.evaluateToConstantValue(expression, bindingTrace, TypeUtils.NO_EXPECTED_TYPE)?.toKtConstantValue() } -} \ No newline at end of file +} diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/base/Kt1DescUtils.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/base/Kt1DescUtils.kt index 01477a9986f..b7bd2b65474 100644 --- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/base/Kt1DescUtils.kt +++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/symbols/descriptorBased/base/Kt1DescUtils.kt @@ -229,6 +229,7 @@ internal fun ConstantValue<*>.toKtConstantValue(): KtConstantValue { val arguments = value.allValueArguments.map { (name, v) -> KtNamedConstantValue(name.asString(), v.toKtConstantValue()) } KtAnnotationConstantValue(value.annotationClass?.classId, arguments, null) } + is ErrorValue -> KtErrorValue(this.toString()) else -> KtUnsupportedConstantValue } } @@ -296,4 +297,4 @@ internal fun DeclarationDescriptor.render(analysisSession: KtFe10AnalysisSession internal fun CallableMemberDescriptor.getSymbolPointerSignature(analysisSession: KtFe10AnalysisSession): String { return render(analysisSession, KtDeclarationRendererOptions.DEFAULT) -} \ No newline at end of file +} 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 ea8ba14ed2f..c53e7074f3c 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 @@ -26,8 +26,12 @@ internal class KtFirCompileTimeConstantProvider( override fun evaluate(expression: KtExpression): KtConstantValue? = withValidityAssertion { when (val fir = expression.getOrBuildFir(firResolveState)) { is FirExpression -> { - FirCompileTimeConstantEvaluator.evaluate(fir)?.let { KtFirConstantValueConverter.toConstantValue(it) } - ?: KtFirConstantValueConverter.toConstantValue(fir, firResolveState.rootModuleSession) + try { + FirCompileTimeConstantEvaluator.evaluate(fir)?.let { KtFirConstantValueConverter.toConstantValue(it) } + ?: KtFirConstantValueConverter.toConstantValue(fir, firResolveState.rootModuleSession) + } catch (e: ArithmeticException) { + KtErrorValue(e.localizedMessage) + } } // For invalid code like the following, // ``` 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 8db41953c06..96b7dcccfcf 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 @@ -98,7 +98,7 @@ internal object FirCompileTimeConstantEvaluator { return evalUnaryOp( function.name.asString(), kind.toCompileTimeType(), - value!! + kind.convertToNumber(value as? Number)!! )?.let { it.toConstantValueKind()?.toConstExpression(source, it) } @@ -113,9 +113,9 @@ internal object FirCompileTimeConstantEvaluator { return evalBinaryOp( function.name.asString(), kind.toCompileTimeType(), - value!!, + kind.convertToNumber(value as? Number)!!, other.kind.toCompileTimeType(), - other.value!! + other.kind.convertToNumber(other.value as? Number)!! )?.let { it.toConstantValueKind()?.toConstExpression(source, it) } diff --git a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/FirCompileTimeConstantEvaluatorTestGenerated.java b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/FirCompileTimeConstantEvaluatorTestGenerated.java index f395e4b8efd..00db8a36074 100644 --- a/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/FirCompileTimeConstantEvaluatorTestGenerated.java +++ b/analysis/analysis-api-fir/tests/org/jetbrains/kotlin/analysis/api/fir/components/FirCompileTimeConstantEvaluatorTestGenerated.java @@ -78,6 +78,12 @@ public class FirCompileTimeConstantEvaluatorTestGenerated extends AbstractFirCom runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_Byte.kt"); } + @Test + @TestMetadata("propertyInit_DivByZero.kt") + public void testPropertyInit_DivByZero() throws Exception { + runTest("analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_DivByZero.kt"); + } + @Test @TestMetadata("propertyInit_Double.kt") public void testPropertyInit_Double() throws Exception { diff --git a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/AbstractCompileTimeConstantEvaluatorTest.kt b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/AbstractCompileTimeConstantEvaluatorTest.kt index bf04df2e68f..6c51aef8e4a 100644 --- a/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/AbstractCompileTimeConstantEvaluatorTest.kt +++ b/analysis/analysis-api-impl-base/tests/org/jetbrains/kotlin/analysis/api/impl/base/test/components/AbstractCompileTimeConstantEvaluatorTest.kt @@ -66,6 +66,7 @@ abstract class AbstractCompileTimeConstantEvaluatorTest( append(", ") append("value=${value})") } + is KtErrorValue -> "KtErrorValue($message)" is KtUnsupportedConstantValue -> "KtUnsupportedConstantValue" } } diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/KtConstantValue.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/KtConstantValue.kt index 262f6adfd59..1c742afd2c1 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/KtConstantValue.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/markers/KtConstantValue.kt @@ -29,6 +29,17 @@ import org.jetbrains.kotlin.types.ConstantValueKind public sealed class KtConstantValue( public open val sourcePsi: KtElement? = null ) + +/** + * This represents an error during expression evaluation or constant conversion. + */ +public class KtErrorValue( + public val message: String +) : KtConstantValue() + +/** + * This represents an unsupported expression used as an annotation value. + */ public object KtUnsupportedConstantValue : KtConstantValue() public class KtArrayConstantValue( diff --git a/analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_DivByZero.kt b/analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_DivByZero.kt new file mode 100644 index 00000000000..0d65cef1bb6 --- /dev/null +++ b/analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_DivByZero.kt @@ -0,0 +1 @@ +val p = 42 / 0 diff --git a/analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_DivByZero.txt b/analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_DivByZero.txt new file mode 100644 index 00000000000..a91aa46bad3 --- /dev/null +++ b/analysis/analysis-api/testData/components/compileTimeConstantEvaluator/propertyInit_DivByZero.txt @@ -0,0 +1,3 @@ +expression: 42 / 0 +constant_value: KtErrorValue(/ by zero) +constant: null diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt index af287bfd593..5d0c3120276 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/constants/constantValues.kt @@ -132,7 +132,7 @@ abstract class ErrorValue : ConstantValue(Unit) { Unit } - @Deprecated("Should not be called, for this is not a real value, but a indication of an error") + @Deprecated("Should not be called, for this is not a real value, but an indication of an error") override val value: Unit get() = throw UnsupportedOperationException()