diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt index a07d4b84394..ca113230091 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/JvmBackendErrors.kt @@ -34,6 +34,8 @@ object JvmBackendErrors { val SCRIPT_CAPTURING_ENUM by error1() val SCRIPT_CAPTURING_ENUM_ENTRY by error1() + val EXCEPTION_IN_CONST_VAL_INITIALIZER by error1() + init { RootDiagnosticRendererFactory.registerFactory(KtDefaultJvmErrorMessages) } @@ -73,5 +75,7 @@ object KtDefaultJvmErrorMessages : BaseDiagnosticRendererFactory() { map.put(JvmBackendErrors.SCRIPT_CAPTURING_INTERFACE, "Interface {0} captures the script class instance. Try to use class instead", STRING) map.put(JvmBackendErrors.SCRIPT_CAPTURING_ENUM, "Enum class {0} captures the script class instance. Try to use class or anonymous object instead", STRING) map.put(JvmBackendErrors.SCRIPT_CAPTURING_ENUM_ENTRY, "Enum entry {0} captures the script class instance. Try to use class or anonymous object instead", STRING) + + map.put(JvmBackendErrors.EXCEPTION_IN_CONST_VAL_INITIALIZER, "An exception occur while evaluating const value initializer: {0}", STRING) } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ConstEvaluationLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ConstEvaluationLowering.kt deleted file mode 100644 index 3a365922938..00000000000 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ConstEvaluationLowering.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.backend.common.lower - -import org.jetbrains.kotlin.backend.common.CommonBackendContext -import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.interpreter.IrInterpreter -import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode -import org.jetbrains.kotlin.ir.interpreter.checker.IrConstTransformer - -val constEvaluationPhase = makeIrModulePhase( - ::ConstEvaluationLowering, - name = "ConstEvaluationLowering", - description = "Evaluate functions that are marked as `Foldable`" -) - -class ConstEvaluationLowering(val context: CommonBackendContext) : FileLoweringPass { - val interpreter = IrInterpreter(context.irBuiltIns) - - override fun lower(irFile: IrFile) { - irFile.transformChildren(IrConstTransformer(interpreter, irFile, mode = EvaluationMode.ONLY_INTRINSIC_CONST), null) - } -} - diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ConstEvaluationLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ConstEvaluationLowering.kt new file mode 100644 index 00000000000..fabaf5ceee9 --- /dev/null +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ConstEvaluationLowering.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.interpreter.IrInterpreter +import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode +import org.jetbrains.kotlin.ir.interpreter.checker.IrConstTransformer +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmBackendErrors + +val constEvaluationPhase = makeIrModulePhase( + ::ConstEvaluationLowering, + name = "ConstEvaluationLowering", + description = "Evaluate functions that are marked as `IntrinsicConstEvaluation`" +) + +// TODO make context common +class ConstEvaluationLowering(val context: JvmBackendContext) : FileLoweringPass { + val interpreter = IrInterpreter(context.irBuiltIns) + + override fun lower(irFile: IrFile) { + val transformer = IrConstTransformer(interpreter, irFile, mode = EvaluationMode.ONLY_INTRINSIC_CONST) { element, error -> + context.ktDiagnosticReporter.at(element, irFile) + .report(JvmBackendErrors.EXCEPTION_IN_CONST_VAL_INITIALIZER, error.description) + } + irFile.transformChildren(transformer, null) + } +} + diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrConstTransformer.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrConstTransformer.kt index 875ed81808b..1ccfeca7533 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrConstTransformer.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/checker/IrConstTransformer.kt @@ -5,11 +5,9 @@ package org.jetbrains.kotlin.ir.interpreter.checker +import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer -import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase -import org.jetbrains.kotlin.ir.declarations.IrField -import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.interpreter.IrInterpreter @@ -19,12 +17,23 @@ import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid class IrConstTransformer( - private val interpreter: IrInterpreter, private val irFile: IrFile, private val mode: EvaluationMode + private val interpreter: IrInterpreter, + private val irFile: IrFile, + private val mode: EvaluationMode, + private val onError: (IrElement, IrErrorExpression) -> Unit = { _, _ -> } ) : IrElementTransformerVoid() { private fun IrExpression.replaceIfError(original: IrExpression): IrExpression { return if (this !is IrErrorExpression) this else original } + private fun IrExpression.reportIfError(original: IrExpression): IrExpression { + if (this is IrErrorExpression) { + onError(original, this) + return original + } + return this + } + override fun visitCall(expression: IrCall): IrExpression { if (expression.accept(IrCompileTimeChecker(mode = mode), null)) { return interpreter.interpret(expression, irFile).replaceIfError(expression) @@ -40,7 +49,8 @@ class IrConstTransformer( if (expression is IrConst<*>) return declaration val isConst = declaration.correspondingPropertySymbol?.owner?.isConst == true if (isConst && expression.accept(IrCompileTimeChecker(declaration, mode), null)) { - initializer.expression = interpreter.interpret(expression, irFile).replaceIfError(expression) + val result = interpreter.interpret(expression, irFile) + initializer.expression = if (isConst) result.reportIfError(expression) else result.replaceIfError(expression) } return declaration @@ -86,7 +96,7 @@ class IrConstTransformer( private fun IrExpression.transformSingleArg(expectedType: IrType): IrExpression { if (this.accept(IrCompileTimeChecker(mode = mode), null)) { - val const = interpreter.interpret(this, irFile).replaceIfError(this) + val const = interpreter.interpret(this, irFile).reportIfError(this) return const.convertToConstIfPossible(expectedType) } else if (this is IrConstructorCall) { transformAnnotation(this) diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter_ir.kt b/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter_ir.kt new file mode 100644 index 00000000000..77431a9876f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter_ir.kt @@ -0,0 +1,11 @@ +// !RENDER_DIAGNOSTICS_FULL_TEXT +// TARGET_BACKEND: JVM_IR +// !DIAGNOSTICS: -CONST_VAL_WITH_NON_CONST_INITIALIZER, -DIVISION_BY_ZERO +// WITH_STDLIB + +const val divideByZero = 1 / 0 +const val trimMarginException = "123".trimMargin(" ") + +//annotation class A(val i: Int, val b: Int) +//@A(1 / 0, 2) +//fun foo() {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter_ir.txt b/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter_ir.txt new file mode 100644 index 00000000000..9a2c1acf569 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter_ir.txt @@ -0,0 +1,4 @@ +package + +public const val divideByZero: kotlin.Int +public const val trimMarginException: kotlin.String diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java index 4d184255629..90e8f7a703b 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java @@ -25,6 +25,12 @@ public class DiagnosticsTestWithJvmIrBackendGenerated extends AbstractDiagnostic KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend"), Pattern.compile("^(.+)\\.kts?$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("exceptionFromInterpreter_ir.kt") + public void testExceptionFromInterpreter_ir() throws Exception { + runTest("compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter_ir.kt"); + } + @Test @TestMetadata("indirectInlineCycle_ir.kt") public void testIndirectInlineCycle_ir() throws Exception { diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/ir/AbstractDumpLoweredIrTest.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/ir/AbstractDumpLoweredIrTest.kt index 59a463d9c62..d7e9b00a84e 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/ir/AbstractDumpLoweredIrTest.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/ir/AbstractDumpLoweredIrTest.kt @@ -5,7 +5,7 @@ package org.jetbrains.kotlin.test.runners.ir -import org.jetbrains.kotlin.backend.common.lower.constEvaluationPhase +import org.jetbrains.kotlin.backend.jvm.lower.constEvaluationPhase import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.test.TargetBackend import org.jetbrains.kotlin.test.backend.handlers.PhasedIrDumpHandler