FIR IDE: make constant evaluator robust to arithmetic exception

This commit is contained in:
Jinseong Jeon
2021-10-28 00:10:20 -07:00
committed by Ilya Kirillov
parent e5bff514b6
commit c3c79b874d
10 changed files with 35 additions and 8 deletions
@@ -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()
}
}
}
@@ -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)
}
}
@@ -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,
// ```
@@ -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)
}
@@ -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 {
@@ -66,6 +66,7 @@ abstract class AbstractCompileTimeConstantEvaluatorTest(
append(", ")
append("value=${value})")
}
is KtErrorValue -> "KtErrorValue($message)"
is KtUnsupportedConstantValue -> "KtUnsupportedConstantValue"
}
}
@@ -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(
@@ -0,0 +1 @@
val p = <expr>42 / 0</expr>
@@ -0,0 +1,3 @@
expression: 42 / 0
constant_value: KtErrorValue(/ by zero)
constant: null
@@ -132,7 +132,7 @@ abstract class ErrorValue : ConstantValue<Unit>(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()