diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt index 74f5944f4b9..58aab0fbbbd 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt @@ -22,22 +22,20 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.config.JvmAnalysisFlags +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality -import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.JvmSimpleFileClassInfo import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl -import org.jetbrains.kotlin.ir.util.IdSignature -import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl -import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable -import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.psi2ir.PsiSourceManager +import org.jetbrains.kotlin.resolve.inline.INLINE_ONLY_ANNOTATION_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.JvmClassName import java.util.* @@ -61,7 +59,8 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa irFile.declarations.forEach { when (it) { - is IrScript -> {} + is IrScript -> { + } is IrClass -> classes.add(it) else -> fileClassMembers.add(it) } @@ -79,19 +78,27 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa private fun createFileClass(irFile: IrFile, fileClassMembers: List): IrClass { val fileEntry = irFile.fileEntry - val fileClassInfo: JvmFileClassInfo? - when (fileEntry) { + val fileClassInfo = when (fileEntry) { is PsiSourceManager.PsiFileEntry -> { val ktFile = context.psiSourceManager.getKtFile(fileEntry) ?: throw AssertionError("Unexpected file entry: $fileEntry") - fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(ktFile) + JvmFileClassUtil.getFileClassInfoNoResolve(ktFile) } is NaiveSourceBasedFileEntryImpl -> { - fileClassInfo = JvmSimpleFileClassInfo(PackagePartClassUtils.getPackagePartFqName(irFile.fqName, fileEntry.name), false) + JvmSimpleFileClassInfo(PackagePartClassUtils.getPackagePartFqName(irFile.fqName, fileEntry.name), false) } else -> error("unknown kind of file entry: $fileEntry") } val isMultifilePart = fileClassInfo.withJvmMultifileClass + + val onlyPrivateDeclarationsAndFeatureIsEnabled = + context.state.languageVersionSettings.supportsFeature(LanguageFeature.PackagePrivateFileClassesWithAllPrivateMembers) && fileClassMembers + .all { + val isPrivate = it is IrDeclarationWithVisibility && DescriptorVisibilities.isPrivate(it.visibility) + val isInlineOnly = it.hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME) + isPrivate || isInlineOnly + } + return IrClassImpl( 0, fileEntry.maxOffset, if (!isMultifilePart || context.state.languageVersionSettings.getFlag(JvmAnalysisFlags.inheritMultifileParts)) @@ -99,7 +106,10 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa symbol = IrClassSymbolImpl(), name = fileClassInfo.fileClassFqName.shortName(), kind = ClassKind.CLASS, - visibility = if (!isMultifilePart) DescriptorVisibilities.PUBLIC else JavaDescriptorVisibilities.PACKAGE_VISIBILITY, + visibility = if (isMultifilePart || onlyPrivateDeclarationsAndFeatureIsEnabled) + JavaDescriptorVisibilities.PACKAGE_VISIBILITY + else + DescriptorVisibilities.PUBLIC, modality = Modality.FINAL ).apply { superTypes = listOf(context.irBuiltIns.anyType) diff --git a/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_after.kt b/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_after.kt new file mode 100644 index 00000000000..29615fc98b9 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_after.kt @@ -0,0 +1,14 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JVM +// !LANGUAGE: +PackagePrivateFileClassesWithAllPrivateMembers + +private fun f() { +} + +private val a = Unit +private val b by lazy { Unit } + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +@kotlin.internal.InlineOnly +public fun g() { +} diff --git a/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_after.txt b/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_after.txt new file mode 100644 index 00000000000..5265d3b0fbe --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_after.txt @@ -0,0 +1,23 @@ +@kotlin.Metadata +final class FileClassWithPrivateDeclarationsOnly_afterKt$b$2 { + // source: 'fileClassWithPrivateDeclarationsOnly_after.kt' + enclosing method FileClassWithPrivateDeclarationsOnly_afterKt.()V + public final static field INSTANCE: FileClassWithPrivateDeclarationsOnly_afterKt$b$2 + inner (anonymous) class FileClassWithPrivateDeclarationsOnly_afterKt$b$2 + static method (): void + method (): void + public synthetic bridge method invoke(): java.lang.Object + public final method invoke(): void +} + +@kotlin.Metadata +final class FileClassWithPrivateDeclarationsOnly_afterKt { + // source: 'fileClassWithPrivateDeclarationsOnly_after.kt' + private final static @org.jetbrains.annotations.NotNull field a: kotlin.Unit + private final static @org.jetbrains.annotations.NotNull field b$delegate: kotlin.Lazy + inner (anonymous) class FileClassWithPrivateDeclarationsOnly_afterKt$b$2 + static method (): void + private final static method f(): void + public final static @kotlin.internal.InlineOnly method g(): void + private final static method getB(): kotlin.Unit +} diff --git a/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_before.kt b/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_before.kt new file mode 100644 index 00000000000..2acfde62879 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_before.kt @@ -0,0 +1,14 @@ +// WITH_RUNTIME +// IGNORE_BACKEND: JVM +// !LANGUAGE: -PackagePrivateFileClassesWithAllPrivateMembers + +private fun f() { +} + +private val a = Unit +private val b by lazy { Unit } + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +@kotlin.internal.InlineOnly +public fun g() { +} diff --git a/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_before.txt b/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_before.txt new file mode 100644 index 00000000000..8e85499a697 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_before.txt @@ -0,0 +1,23 @@ +@kotlin.Metadata +final class FileClassWithPrivateDeclarationsOnly_beforeKt$b$2 { + // source: 'fileClassWithPrivateDeclarationsOnly_before.kt' + enclosing method FileClassWithPrivateDeclarationsOnly_beforeKt.()V + public final static field INSTANCE: FileClassWithPrivateDeclarationsOnly_beforeKt$b$2 + inner (anonymous) class FileClassWithPrivateDeclarationsOnly_beforeKt$b$2 + static method (): void + method (): void + public synthetic bridge method invoke(): java.lang.Object + public final method invoke(): void +} + +@kotlin.Metadata +public final class FileClassWithPrivateDeclarationsOnly_beforeKt { + // source: 'fileClassWithPrivateDeclarationsOnly_before.kt' + private final static @org.jetbrains.annotations.NotNull field a: kotlin.Unit + private final static @org.jetbrains.annotations.NotNull field b$delegate: kotlin.Lazy + inner (anonymous) class FileClassWithPrivateDeclarationsOnly_beforeKt$b$2 + static method (): void + private final static method f(): void + public final static @kotlin.internal.InlineOnly method g(): void + private final static method getB(): kotlin.Unit +} diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 382d70c5f14..0707ec688df 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -90,6 +90,16 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { runTest("compiler/testData/codegen/bytecodeListing/extension.kt"); } + @TestMetadata("fileClassWithPrivateDeclarationsOnly_after.kt") + public void testFileClassWithPrivateDeclarationsOnly_after() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_after.kt"); + } + + @TestMetadata("fileClassWithPrivateDeclarationsOnly_before.kt") + public void testFileClassWithPrivateDeclarationsOnly_before() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_before.kt"); + } + @TestMetadata("immutableCollection.kt") public void testImmutableCollection() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/immutableCollection.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java index d9e1a3e75aa..fabfa8b0978 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBytecodeListingTestGenerated.java @@ -90,6 +90,16 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes runTest("compiler/testData/codegen/bytecodeListing/extension.kt"); } + @TestMetadata("fileClassWithPrivateDeclarationsOnly_after.kt") + public void testFileClassWithPrivateDeclarationsOnly_after() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_after.kt"); + } + + @TestMetadata("fileClassWithPrivateDeclarationsOnly_before.kt") + public void testFileClassWithPrivateDeclarationsOnly_before() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/fileClassWithPrivateDeclarationsOnly_before.kt"); + } + @TestMetadata("immutableCollection.kt") public void testImmutableCollection() throws Exception { runTest("compiler/testData/codegen/bytecodeListing/immutableCollection.kt"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index be9702f8928..bebb209059d 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -145,6 +145,8 @@ enum class LanguageFeature( AllowSealedInheritorsInDifferentFilesOfSamePackage(KOTLIN_1_5), SealedInterfaces(KOTLIN_1_5), JvmIrEnabledByDefault(KOTLIN_1_5), + // Disabled until the breaking change is approved by the committee, see KT-10884. + PackagePrivateFileClassesWithAllPrivateMembers(KOTLIN_1_5, defaultState = State.DISABLED), /* * Improvements include the following: