From 6069aaee9c6522c850db5fc25e967f5c16cdb70d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 24 Jul 2023 17:24:35 +0200 Subject: [PATCH] K2: report JvmMultifileClass+JvmSynthetic error in JVM backend Specifically, the case when not all parts of a multifile class are annotated with `@JvmSynthetic`. Report the error on the `@JvmMultifileClass` annotation instead of the package directive, because the latter is difficult to find via IR. This fixes the test FirLightTreeDiagnosticsTestWithJvmIrBackendGenerated.MultifileClasses.testJvmSynthetic. #KT-59586 --- .../resolve/jvm/diagnostics/JvmBackendErrors.kt | 6 ++++++ .../backend/jvm/lower/GenerateMultifileFacades.kt | 13 +++++++------ .../multifileClasses/jvmSynthetic.kt | 8 ++++---- 3 files changed, 17 insertions(+), 10 deletions(-) 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 5c773dbca85..6d14296c022 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 @@ -37,6 +37,8 @@ object JvmBackendErrors { val INLINE_CALL_CYCLE by error1() + val NOT_ALL_MULTIFILE_CLASS_PARTS_ARE_JVM_SYNTHETIC by error0() + init { RootDiagnosticRendererFactory.registerFactory(KtDefaultJvmErrorMessages) } @@ -72,5 +74,9 @@ object KtDefaultJvmErrorMessages : BaseDiagnosticRendererFactory() { 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.INLINE_CALL_CYCLE, "The ''{0}'' invocation is a part of inline cycle", NAME) + map.put( + JvmBackendErrors.NOT_ALL_MULTIFILE_CLASS_PARTS_ARE_JVM_SYNTHETIC, + "All of multi-file class parts should be annotated with @JvmSynthetic if at least one of them is" + ) } } diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt index 830306a75e3..147e4bc85a0 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/GenerateMultifileFacades.kt @@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.MultifileFacadeFileEntry import org.jetbrains.kotlin.backend.jvm.ir.fileParent -import org.jetbrains.kotlin.backend.jvm.ir.getKtFile import org.jetbrains.kotlin.backend.jvm.isMultifileBridge import org.jetbrains.kotlin.config.JvmAnalysisFlags import org.jetbrains.kotlin.descriptors.DescriptorVisibilities @@ -38,9 +37,10 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities +import org.jetbrains.kotlin.name.JvmNames import org.jetbrains.kotlin.name.JvmNames.JVM_SYNTHETIC_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.inline.INLINE_ONLY_ANNOTATION_FQ_NAME -import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm +import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmBackendErrors internal val generateMultifileFacadesPhase = makeCustomPhase( name = "GenerateMultifileFacades", @@ -118,11 +118,12 @@ private fun generateMultifileFacades( annotations = annotations + partClasses.first().getAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME)!!.deepCopyWithSymbols() } else if (nonJvmSyntheticParts.size < partClasses.size) { for (part in nonJvmSyntheticParts) { - val partFile = part.fileParent.getKtFile() ?: error("Not a KtFile: ${part.render()} ${part.fileParent}") + val partFile = part.fileParent // If at least one of parts is annotated with @JvmSynthetic, then all other parts should also be annotated. - // We report this error on the package directive for each non-@JvmSynthetic part. - context.state.diagnostics.report( - ErrorsJvm.NOT_ALL_MULTIFILE_CLASS_PARTS_ARE_JVM_SYNTHETIC.on(partFile.packageDirective ?: partFile) + // We report this error on the `@JvmMultifileClass` annotation of each non-@JvmSynthetic part. + val annotation = partFile.annotations.singleOrNull { it.isAnnotationWithEqualFqName(JvmNames.JVM_MULTIFILE_CLASS) } + context.ktDiagnosticReporter.at(annotation ?: partFile, partFile).report( + JvmBackendErrors.NOT_ALL_MULTIFILE_CLASS_PARTS_ARE_JVM_SYNTHETIC ) } } diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/multifileClasses/jvmSynthetic.kt b/compiler/testData/diagnostics/testsWithJvmBackend/multifileClasses/jvmSynthetic.kt index 029a8d9496e..346ac9ed5fd 100644 --- a/compiler/testData/diagnostics/testsWithJvmBackend/multifileClasses/jvmSynthetic.kt +++ b/compiler/testData/diagnostics/testsWithJvmBackend/multifileClasses/jvmSynthetic.kt @@ -3,8 +3,8 @@ // FILE: f.kt @file:JvmName("Foo") -@file:JvmMultifileClass -package test +@file:JvmMultifileClass +package test fun f() {} @@ -20,8 +20,8 @@ val g = "" // FILE: h.kt @file:JvmName("Foo") -@file:JvmMultifileClass -package test +@file:JvmMultifileClass +package test fun h() {}