diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt index 02057a2d236..5a0a9466e82 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrConverter.kt @@ -5,9 +5,12 @@ package org.jetbrains.kotlin.fir.backend +import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.KtPsiSourceFileLinesMapping import org.jetbrains.kotlin.KtSourceFileLinesMappingFromLineStartOffsets +import org.jetbrains.kotlin.backend.common.CommonBackendErrors +import org.jetbrains.kotlin.backend.common.sourceElement import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.AnalysisFlags @@ -400,8 +403,8 @@ class Fir2IrConverter( private fun evaluateConstants(irModuleFragment: IrModuleFragment, fir2IrConfiguration: Fir2IrConfiguration) { val firModuleDescriptor = irModuleFragment.descriptor as? FirModuleDescriptor val targetPlatform = firModuleDescriptor?.platform - val languageVersionSettings = firModuleDescriptor?.session?.languageVersionSettings - val intrinsicConstEvaluation = languageVersionSettings?.supportsFeature(LanguageFeature.IntrinsicConstEvaluation) == true + val languageVersionSettings = firModuleDescriptor?.session?.languageVersionSettings ?: return + val intrinsicConstEvaluation = languageVersionSettings.supportsFeature(LanguageFeature.IntrinsicConstEvaluation) == true val configuration = IrInterpreterConfiguration( platform = targetPlatform, @@ -409,8 +412,19 @@ class Fir2IrConverter( ) val interpreter = IrInterpreter(IrInterpreterEnvironment(irModuleFragment.irBuiltins, configuration)) val mode = if (intrinsicConstEvaluation) EvaluationMode.ONLY_INTRINSIC_CONST else EvaluationMode.ONLY_BUILTINS + val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(fir2IrConfiguration.diagnosticReporter, languageVersionSettings) irModuleFragment.files.forEach { - it.transformConst(interpreter, mode, fir2IrConfiguration.evaluatedConstTracker, fir2IrConfiguration.inlineConstTracker) + it.transformConst( + interpreter, + mode, + fir2IrConfiguration.evaluatedConstTracker, + fir2IrConfiguration.inlineConstTracker, + onError = { irFile, element, error -> + // We are using exactly this overload of `at` to eliminate differences between PSI and LightTree render + ktDiagnosticReporter.at(element.sourceElement(), element, irFile) + .report(CommonBackendErrors.EVALUATION_ERROR, error.description) + } + ) } } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticsTestWithJvmIrBackendGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticsTestWithJvmIrBackendGenerated.java index 9a3391a8bc5..ff919819f93 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticsTestWithJvmIrBackendGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticsTestWithJvmIrBackendGenerated.java @@ -24,12 +24,6 @@ public class FirPsiDiagnosticsTestWithJvmIrBackendGenerated extends AbstractFirP KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true); } - @Test - @TestMetadata("exceptionFromInterpreter.kt") - public void testExceptionFromInterpreter() throws Exception { - runTest("compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter.kt"); - } - @Test @TestMetadata("indirectInlineCycle.kt") public void testIndirectInlineCycle() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/FirLightTreeWithInterpreterDiagnosticsTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/FirLightTreeWithInterpreterDiagnosticsTestGenerated.java new file mode 100644 index 00000000000..6a53467ff78 --- /dev/null +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/FirLightTreeWithInterpreterDiagnosticsTestGenerated.java @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2023 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.test.runners.ir; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.test.generators.GenerateCompilerTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/diagnostics/irInterpreter") +@TestDataPath("$PROJECT_ROOT") +public class FirLightTreeWithInterpreterDiagnosticsTestGenerated extends AbstractFirLightTreeWithInterpreterDiagnosticsTest { + @Test + public void testAllFilesPresentInIrInterpreter() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/irInterpreter"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("exceptionFromInterpreter.kt") + public void testExceptionFromInterpreter() throws Exception { + runTest("compiler/testData/diagnostics/irInterpreter/exceptionFromInterpreter.kt"); + } +} diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/FirPsiWithInterpreterDiagnosticsTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/FirPsiWithInterpreterDiagnosticsTestGenerated.java new file mode 100644 index 00000000000..216dbeff007 --- /dev/null +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/ir/FirPsiWithInterpreterDiagnosticsTestGenerated.java @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2023 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.test.runners.ir; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.util.KtTestUtil; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.test.generators.GenerateCompilerTestsKt}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/diagnostics/irInterpreter") +@TestDataPath("$PROJECT_ROOT") +public class FirPsiWithInterpreterDiagnosticsTestGenerated extends AbstractFirPsiWithInterpreterDiagnosticsTest { + @Test + public void testAllFilesPresentInIrInterpreter() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/irInterpreter"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("exceptionFromInterpreter.kt") + public void testExceptionFromInterpreter() throws Exception { + runTest("compiler/testData/diagnostics/irInterpreter/exceptionFromInterpreter.kt"); + } +} 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 51c9a1c6017..88527e1089e 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 @@ -6,9 +6,11 @@ package org.jetbrains.kotlin.resolve.jvm.diagnostics import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.diagnostics.* +import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT +import org.jetbrains.kotlin.diagnostics.error0 +import org.jetbrains.kotlin.diagnostics.error1 +import org.jetbrains.kotlin.diagnostics.error2 import org.jetbrains.kotlin.diagnostics.rendering.* import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers.STRING import org.jetbrains.kotlin.resolve.MemberComparator @@ -31,9 +33,6 @@ object JvmBackendErrors { val SCRIPT_CAPTURING_ENUM by error1() val SCRIPT_CAPTURING_ENUM_ENTRY by error1() - val EXCEPTION_IN_CONST_VAL_INITIALIZER by error1() - val EXCEPTION_IN_CONST_EXPRESSION by warning1() - init { RootDiagnosticRendererFactory.registerFactory(KtDefaultJvmErrorMessages) } @@ -67,8 +66,5 @@ 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, "Cannot evaluate constant expression: {0}", STRING) - map.put(JvmBackendErrors.EXCEPTION_IN_CONST_EXPRESSION, "Constant expression will throw an exception at runtime: {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 index 09b1eec7688..e6d320db6a3 100644 --- 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 @@ -8,25 +8,18 @@ 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.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.languageVersionSettings -import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.expressions.IrErrorExpression import org.jetbrains.kotlin.ir.interpreter.IrInterpreter import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode import org.jetbrains.kotlin.ir.interpreter.transformer.preprocessForConstTransformer import org.jetbrains.kotlin.ir.interpreter.transformer.runConstOptimizations -import org.jetbrains.kotlin.ir.interpreter.transformer.transformConst class ConstEvaluationLowering( val context: CommonBackendContext, private val suppressErrors: Boolean = context.configuration.getBoolean(CommonConfigurationKeys.IGNORE_CONST_OPTIMIZATION_ERRORS), configuration: IrInterpreterConfiguration = IrInterpreterConfiguration(printOnlyExceptionMessage = true), - private val onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> }, - private val onError: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> }, ) : FileLoweringPass { private val interpreter = IrInterpreter(IrInterpreterEnvironment(context.irBuiltIns, configuration), emptyMap()) private val evaluatedConstTracker = context.configuration[CommonConfigurationKeys.EVALUATED_CONST_TRACKER] @@ -37,7 +30,7 @@ class ConstEvaluationLowering( val useFir = context.configuration[CommonConfigurationKeys.USE_FIR] == true val preprocessedFile = if (useFir) irFile else irFile.preprocessForConstTransformer(interpreter, mode) preprocessedFile.runConstOptimizations( - interpreter, mode, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressErrors + interpreter, mode, evaluatedConstTracker, inlineConstTracker, suppressErrors ) } } diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index cb8242dd46e..89a2805b90f 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -33,7 +33,6 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities import org.jetbrains.kotlin.name.NameUtils -import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmBackendErrors private var patchParentPhases = 0 @@ -328,19 +327,7 @@ private val apiVersionIsAtLeastEvaluationPhase = makeIrModulePhase( ) private val constEvaluationPhase = makeIrModulePhase( - { - ConstEvaluationLowering( - it, - onWarning = { irFile, element, warning -> - it.ktDiagnosticReporter.at(element, irFile) - .report(JvmBackendErrors.EXCEPTION_IN_CONST_EXPRESSION, warning.description) - }, - onError = { irFile, element, error -> - it.ktDiagnosticReporter.at(element, irFile) - .report(JvmBackendErrors.EXCEPTION_IN_CONST_VAL_INITIALIZER, error.description) - } - ) - }, + ::ConstEvaluationLowering, name = "ConstEvaluationLowering", description = "Evaluate functions that are marked as `IntrinsicConstEvaluation`" ) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt index 7553aeb5821..fc6fc1a1752 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrTreeBuildUtils.kt @@ -167,6 +167,8 @@ internal fun IrBuiltIns.emptyArrayConstructor(arrayType: IrType): IrConstructorC } internal fun IrConst<*>.toConstantValue(): ConstantValue<*> { + if (value == null) return NullValue + val constType = this.type.makeNotNull().removeAnnotations() return when (this.type.getPrimitiveType()) { PrimitiveType.BOOLEAN -> BooleanValue(this.value as Boolean) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt index f9bd673af93..e998269b715 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/transformer/IrConstTransformer.kt @@ -14,7 +14,10 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.interpreter.IrInterpreter import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration -import org.jetbrains.kotlin.ir.interpreter.checker.* +import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode +import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterChecker +import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterCheckerData +import org.jetbrains.kotlin.ir.interpreter.checker.IrInterpreterCommonChecker import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterConstGetterPreprocessor import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterKCallableNamePreprocessor import org.jetbrains.kotlin.ir.interpreter.preprocessor.IrInterpreterPreprocessorData @@ -58,13 +61,11 @@ fun IrFile.runConstOptimizations( mode: EvaluationMode, evaluatedConstTracker: EvaluatedConstTracker? = null, inlineConstTracker: InlineConstTracker? = null, - onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> }, - onError: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> }, suppressExceptions: Boolean = false, ) { val checker = IrInterpreterCommonChecker() val irConstExpressionTransformer = IrConstAllTransformer( - interpreter, this, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions + interpreter, this, mode, checker, evaluatedConstTracker, inlineConstTracker, { _, _, _ -> }, { _, _, _ -> }, suppressExceptions ) this.transform(irConstExpressionTransformer, IrConstTransformer.Data()) } diff --git a/compiler/testData/diagnostics/irInterpreter/exceptionFromInterpreter.fir.ir.diag.txt b/compiler/testData/diagnostics/irInterpreter/exceptionFromInterpreter.fir.ir.diag.txt new file mode 100644 index 00000000000..a7dd3c6a941 --- /dev/null +++ b/compiler/testData/diagnostics/irInterpreter/exceptionFromInterpreter.fir.ir.diag.txt @@ -0,0 +1,5 @@ +/exceptionFromInterpreter.kt:(197,200): error: Cannot evaluate constant expression: / by zero + +/exceptionFromInterpreter.kt:(239,254): error: Cannot evaluate constant expression: marginPrefix must be non-blank string. + +/exceptionFromInterpreter.kt:(305,308): error: Cannot evaluate constant expression: / by zero diff --git a/compiler/testData/diagnostics/irInterpreter/exceptionFromInterpreter.kt b/compiler/testData/diagnostics/irInterpreter/exceptionFromInterpreter.kt new file mode 100644 index 00000000000..7dfbb4edfb0 --- /dev/null +++ b/compiler/testData/diagnostics/irInterpreter/exceptionFromInterpreter.kt @@ -0,0 +1,14 @@ +// FIR_IDENTICAL +// !RENDER_IR_DIAGNOSTICS_FULL_TEXT +// !LANGUAGE: +IntrinsicConstEvaluation +// TARGET_BACKEND: JVM_IR +// !DIAGNOSTICS: -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() {} diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter.kt b/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter.kt deleted file mode 100644 index 26f1f2656d5..00000000000 --- a/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter.kt +++ /dev/null @@ -1,15 +0,0 @@ -// FIR_IDENTICAL -// !RENDER_ALL_DIAGNOSTICS_FULL_TEXT -// TARGET_BACKEND: JVM_IR -// !DIAGNOSTICS: -CONST_VAL_WITH_NON_CONST_INITIALIZER, -DIVISION_BY_ZERO -// WITH_STDLIB - -const val divideByZero = 1 / 0 -val disivionByZeroWarn = 1 / 0 -const val trimMarginException = "123".trimMargin(" ") - -// TODO must report all these exceptions directly from fir2ir -//annotation class A(val i: Int, val b: Int) -// -//@A(1 / 0, 2) -//fun foo() {} diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter.txt b/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter.txt deleted file mode 100644 index e5b0d3625ee..00000000000 --- a/compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter.txt +++ /dev/null @@ -1,5 +0,0 @@ -package - -public val disivionByZeroWarn: kotlin.Int -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 0afd4374193..84c15562b79 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,12 +25,6 @@ public class DiagnosticsTestWithJvmIrBackendGenerated extends AbstractDiagnostic KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend"), Pattern.compile("^(.+)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true); } - @Test - @TestMetadata("exceptionFromInterpreter.kt") - public void testExceptionFromInterpreter() throws Exception { - runTest("compiler/testData/diagnostics/testsWithJvmBackend/exceptionFromInterpreter.kt"); - } - @Test @TestMetadata("indirectInlineCycle.kt") public void testIndirectInlineCycle() throws Exception { diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrDiagnosticsHandler.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrDiagnosticsHandler.kt index e38f7380fe4..bfc7857ffa7 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrDiagnosticsHandler.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/ir/IrDiagnosticsHandler.kt @@ -7,8 +7,10 @@ package org.jetbrains.kotlin.test.backend.ir import org.jetbrains.kotlin.test.FirParser import org.jetbrains.kotlin.test.backend.handlers.AbstractIrHandler +import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue +import org.jetbrains.kotlin.test.frontend.fir.handlers.FullDiagnosticsRenderer import org.jetbrains.kotlin.test.frontend.fir.handlers.diagnosticCodeMetaInfos import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.services.* @@ -20,6 +22,8 @@ class IrDiagnosticsHandler(testServices: TestServices) : AbstractIrHandler(testS private val diagnosticsService: DiagnosticsService get() = testServices.diagnosticsService + private val fullDiagnosticsRenderer = FullDiagnosticsRenderer(DiagnosticsDirectives.RENDER_IR_DIAGNOSTICS_FULL_TEXT) + override fun processModule(module: TestModule, info: IrBackendInput) { val diagnosticsByFilePath = info.diagnosticReporter.diagnosticsByFilePath for (currentModule in testServices.moduleStructure.modules) { @@ -34,10 +38,13 @@ class IrDiagnosticsHandler(testServices: TestServices) : AbstractIrHandler(testS lightTreeEnabled, lightTreeComparingModeEnabled ) globalMetadataInfoHandler.addMetadataInfosForFile(file, diagnosticsMetadataInfos) + fullDiagnosticsRenderer.storeFullDiagnosticRender(module, diagnostics, file) } } } } - override fun processAfterAllModules(someAssertionWasFailed: Boolean) {} + override fun processAfterAllModules(someAssertionWasFailed: Boolean) { + fullDiagnosticsRenderer.assertCollectedDiagnostics(testServices, ".fir.ir.diag.txt") + } } \ No newline at end of file diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/DiagnosticsDirectives.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/DiagnosticsDirectives.kt index 24ad8412358..7aeb469c246 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/DiagnosticsDirectives.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/DiagnosticsDirectives.kt @@ -92,4 +92,8 @@ object DiagnosticsDirectives : SimpleDirectivesContainer() { val RENDER_ALL_DIAGNOSTICS_FULL_TEXT by directive( description = "Render both frontend and backend diagnostic texts to .diag.txt" ) + + val RENDER_IR_DIAGNOSTICS_FULL_TEXT by directive( + description = "Render IR diagnostic texts to .ir.diag.txt" + ) } diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt index 7c7af5dccc3..78cc9a6044a 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives import org.jetbrains.kotlin.test.directives.model.DirectivesContainer +import org.jetbrains.kotlin.test.directives.model.SimpleDirective import org.jetbrains.kotlin.test.directives.model.singleValue import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact import org.jetbrains.kotlin.test.model.TestFile @@ -55,6 +56,31 @@ import org.jetbrains.kotlin.test.utils.MultiModuleInfoDumper import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly +class FullDiagnosticsRenderer(private val directive: SimpleDirective) { + private val dumper: MultiModuleInfoDumper = MultiModuleInfoDumper(moduleHeaderTemplate = "// -- Module: <%s> --") + + fun assertCollectedDiagnostics(testServices: TestServices, expectedExtension: String) { + if (dumper.isEmpty()) return + val resultDump = dumper.generateResultingDump() + val testDataFile = testServices.moduleStructure.originalTestDataFiles.first() + val expectedFile = testDataFile.parentFile.resolve("${testDataFile.nameWithoutExtension.removeSuffix(".fir")}$expectedExtension") + testServices.assertions.assertEqualsToFile(expectedFile, resultDump) + } + + fun storeFullDiagnosticRender(module: TestModule, diagnostics: List, file: TestFile) { + if (directive !in module.directives) return + if (diagnostics.isEmpty()) return + + val reportedDiagnostics = diagnostics.sortedBy { it.textRanges.first().startOffset }.map { + val severity = AnalyzerWithCompilerReport.convertSeverity(it.severity).toString().toLowerCaseAsciiOnly() + val message = RootDiagnosticRendererFactory(it).render(it) + "/${file.name}:${it.textRanges.first()}: $severity: $message" + } + + dumper.builderForModule(module).appendLine(reportedDiagnostics.joinToString(separator = "\n\n")) + } +} + @OptIn(SymbolInternals::class) class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(testServices) { private val globalMetadataInfoHandler: GlobalMetadataInfoHandler @@ -69,14 +95,10 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes override val additionalServices: List = listOf(service(::DiagnosticsService)) - private val dumper: MultiModuleInfoDumper = MultiModuleInfoDumper(moduleHeaderTemplate = "// -- Module: <%s> --") + private val fullDiagnosticsRenderer = FullDiagnosticsRenderer(DiagnosticsDirectives.RENDER_DIAGNOSTICS_FULL_TEXT) override fun processAfterAllModules(someAssertionWasFailed: Boolean) { - if (dumper.isEmpty()) return - val resultDump = dumper.generateResultingDump() - val testDataFile = testServices.moduleStructure.originalTestDataFiles.first() - val expectedFile = testDataFile.parentFile.resolve("${testDataFile.nameWithoutFirExtension}.fir.diag.txt") - assertions.assertEqualsToFile(expectedFile, resultDump) + fullDiagnosticsRenderer.assertCollectedDiagnostics(testServices, ".fir.diag.txt") } override fun processModule(module: TestModule, info: FirOutputArtifact) { @@ -109,7 +131,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes globalMetadataInfoHandler.addMetadataInfosForFile(file, diagnosticsMetadataInfos) collectSyntaxDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled, forceRenderArguments) collectDebugInfoDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled) - checkFullDiagnosticRender(module, diagnostics, file) + fullDiagnosticsRenderer.storeFullDiagnosticRender(module, diagnostics, file) } } } @@ -340,19 +362,6 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes is FirCallableSymbol<*> -> callableId.asFqNameForDebugInfo().toUnsafe() else -> null } - - private fun checkFullDiagnosticRender(module: TestModule, diagnostics: List, file: TestFile) { - if (DiagnosticsDirectives.RENDER_DIAGNOSTICS_FULL_TEXT !in module.directives) return - if (diagnostics.isEmpty()) return - - val reportedDiagnostics = diagnostics.sortedBy { it.textRanges.first().startOffset }.map { - val severity = AnalyzerWithCompilerReport.convertSeverity(it.severity).toString().toLowerCaseAsciiOnly() - val message = RootDiagnosticRendererFactory(it).render(it) - "/${file.name}:${it.textRanges.first()}: $severity: $message" - } - - dumper.builderForModule(module).appendLine(reportedDiagnostics.joinToString(separator = "\n\n")) - } } fun List.diagnosticCodeMetaInfos( diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/ir/AbstractFirWithInterpreterDiagnosticsTest.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/ir/AbstractFirWithInterpreterDiagnosticsTest.kt new file mode 100644 index 00000000000..10cfcf6bc48 --- /dev/null +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/ir/AbstractFirWithInterpreterDiagnosticsTest.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2023 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.test.runners.ir + +import org.jetbrains.kotlin.test.FirParser +import org.jetbrains.kotlin.test.TargetBackend +import org.jetbrains.kotlin.test.backend.ir.IrDiagnosticsHandler +import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder +import org.jetbrains.kotlin.test.builders.irHandlersStep +import org.jetbrains.kotlin.test.directives.configureFirParser +import org.jetbrains.kotlin.test.frontend.fir.Fir2IrResultsConverter +import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerWithTargetBackendTest +import org.jetbrains.kotlin.test.runners.baseFirDiagnosticTestConfiguration + +abstract class AbstractFirWithInterpreterDiagnosticsTest(val parser: FirParser) : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR) { + override fun TestConfigurationBuilder.configuration() { + configureFirParser(parser) + baseFirDiagnosticTestConfiguration() + + facadeStep(::Fir2IrResultsConverter) + irHandlersStep { + useHandlers( + ::IrDiagnosticsHandler + ) + } + } +} + +open class AbstractFirPsiWithInterpreterDiagnosticsTest : AbstractFirWithInterpreterDiagnosticsTest(FirParser.Psi) + +open class AbstractFirLightTreeWithInterpreterDiagnosticsTest : AbstractFirWithInterpreterDiagnosticsTest(FirParser.LightTree) diff --git a/compiler/tests-for-compiler-generator/tests/org/jetbrains/kotlin/test/generators/GenerateJUnit5CompilerTests.kt b/compiler/tests-for-compiler-generator/tests/org/jetbrains/kotlin/test/generators/GenerateJUnit5CompilerTests.kt index 3cc0639137c..646c40790fb 100644 --- a/compiler/tests-for-compiler-generator/tests/org/jetbrains/kotlin/test/generators/GenerateJUnit5CompilerTests.kt +++ b/compiler/tests-for-compiler-generator/tests/org/jetbrains/kotlin/test/generators/GenerateJUnit5CompilerTests.kt @@ -10,9 +10,7 @@ import org.jetbrains.kotlin.generators.util.TestGeneratorUtil import org.jetbrains.kotlin.test.TargetBackend import org.jetbrains.kotlin.test.runners.* import org.jetbrains.kotlin.test.runners.codegen.* -import org.jetbrains.kotlin.test.runners.ir.AbstractClassicJvmIrTextTest -import org.jetbrains.kotlin.test.runners.ir.AbstractFirLightTreeJvmIrTextTest -import org.jetbrains.kotlin.test.runners.ir.AbstractFirPsiJvmIrTextTest +import org.jetbrains.kotlin.test.runners.ir.* import org.jetbrains.kotlin.test.runners.ir.interpreter.AbstractJvmIrInterpreterAfterFirPsi2IrTest import org.jetbrains.kotlin.test.runners.ir.interpreter.AbstractJvmIrInterpreterAfterPsi2IrTest import org.jetbrains.kotlin.test.utils.CUSTOM_TEST_DATA_EXTENSION_PATTERN @@ -321,6 +319,14 @@ fun generateJUnit5CompilerTests(args: Array) { model("debug/localVariables") } + testClass { + model("diagnostics/irInterpreter") + } + + testClass { + model("diagnostics/irInterpreter") + } + testClass { model("diagnostics/testsWithJvmBackend", excludedPattern = excludedCustomTestdataPattern) }