[JVM IR] Make file classes with all private members package-private

This commit is contained in:
Iaroslav Postovalov
2020-12-26 21:42:46 +07:00
committed by Alexander Udalov
parent 032c64669c
commit 77180a5b13
8 changed files with 117 additions and 11 deletions
@@ -22,22 +22,20 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.config.JvmAnalysisFlags import org.jetbrains.kotlin.config.JvmAnalysisFlags
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.fileClasses.JvmSimpleFileClassInfo import org.jetbrains.kotlin.fileClasses.JvmSimpleFileClassInfo
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.*
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.load.java.JavaDescriptorVisibilities import org.jetbrains.kotlin.load.java.JavaDescriptorVisibilities
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.psi2ir.PsiSourceManager 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 org.jetbrains.kotlin.resolve.jvm.JvmClassName
import java.util.* import java.util.*
@@ -61,7 +59,8 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa
irFile.declarations.forEach { irFile.declarations.forEach {
when (it) { when (it) {
is IrScript -> {} is IrScript -> {
}
is IrClass -> classes.add(it) is IrClass -> classes.add(it)
else -> fileClassMembers.add(it) else -> fileClassMembers.add(it)
} }
@@ -79,19 +78,27 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa
private fun createFileClass(irFile: IrFile, fileClassMembers: List<IrDeclaration>): IrClass { private fun createFileClass(irFile: IrFile, fileClassMembers: List<IrDeclaration>): IrClass {
val fileEntry = irFile.fileEntry val fileEntry = irFile.fileEntry
val fileClassInfo: JvmFileClassInfo? val fileClassInfo = when (fileEntry) {
when (fileEntry) {
is PsiSourceManager.PsiFileEntry -> { is PsiSourceManager.PsiFileEntry -> {
val ktFile = context.psiSourceManager.getKtFile(fileEntry) val ktFile = context.psiSourceManager.getKtFile(fileEntry)
?: throw AssertionError("Unexpected file entry: $fileEntry") ?: throw AssertionError("Unexpected file entry: $fileEntry")
fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(ktFile) JvmFileClassUtil.getFileClassInfoNoResolve(ktFile)
} }
is NaiveSourceBasedFileEntryImpl -> { 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") else -> error("unknown kind of file entry: $fileEntry")
} }
val isMultifilePart = fileClassInfo.withJvmMultifileClass 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( return IrClassImpl(
0, fileEntry.maxOffset, 0, fileEntry.maxOffset,
if (!isMultifilePart || context.state.languageVersionSettings.getFlag(JvmAnalysisFlags.inheritMultifileParts)) if (!isMultifilePart || context.state.languageVersionSettings.getFlag(JvmAnalysisFlags.inheritMultifileParts))
@@ -99,7 +106,10 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa
symbol = IrClassSymbolImpl(), symbol = IrClassSymbolImpl(),
name = fileClassInfo.fileClassFqName.shortName(), name = fileClassInfo.fileClassFqName.shortName(),
kind = ClassKind.CLASS, 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 modality = Modality.FINAL
).apply { ).apply {
superTypes = listOf(context.irBuiltIns.anyType) superTypes = listOf(context.irBuiltIns.anyType)
@@ -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() {
}
@@ -0,0 +1,23 @@
@kotlin.Metadata
final class FileClassWithPrivateDeclarationsOnly_afterKt$b$2 {
// source: 'fileClassWithPrivateDeclarationsOnly_after.kt'
enclosing method FileClassWithPrivateDeclarationsOnly_afterKt.<clinit>()V
public final static field INSTANCE: FileClassWithPrivateDeclarationsOnly_afterKt$b$2
inner (anonymous) class FileClassWithPrivateDeclarationsOnly_afterKt$b$2
static method <clinit>(): void
method <init>(): 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 <clinit>(): void
private final static method f(): void
public final static @kotlin.internal.InlineOnly method g(): void
private final static method getB(): kotlin.Unit
}
@@ -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() {
}
@@ -0,0 +1,23 @@
@kotlin.Metadata
final class FileClassWithPrivateDeclarationsOnly_beforeKt$b$2 {
// source: 'fileClassWithPrivateDeclarationsOnly_before.kt'
enclosing method FileClassWithPrivateDeclarationsOnly_beforeKt.<clinit>()V
public final static field INSTANCE: FileClassWithPrivateDeclarationsOnly_beforeKt$b$2
inner (anonymous) class FileClassWithPrivateDeclarationsOnly_beforeKt$b$2
static method <clinit>(): void
method <init>(): 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 <clinit>(): void
private final static method f(): void
public final static @kotlin.internal.InlineOnly method g(): void
private final static method getB(): kotlin.Unit
}
@@ -90,6 +90,16 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
runTest("compiler/testData/codegen/bytecodeListing/extension.kt"); 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") @TestMetadata("immutableCollection.kt")
public void testImmutableCollection() throws Exception { public void testImmutableCollection() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/immutableCollection.kt"); runTest("compiler/testData/codegen/bytecodeListing/immutableCollection.kt");
@@ -90,6 +90,16 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
runTest("compiler/testData/codegen/bytecodeListing/extension.kt"); 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") @TestMetadata("immutableCollection.kt")
public void testImmutableCollection() throws Exception { public void testImmutableCollection() throws Exception {
runTest("compiler/testData/codegen/bytecodeListing/immutableCollection.kt"); runTest("compiler/testData/codegen/bytecodeListing/immutableCollection.kt");
@@ -145,6 +145,8 @@ enum class LanguageFeature(
AllowSealedInheritorsInDifferentFilesOfSamePackage(KOTLIN_1_5), AllowSealedInheritorsInDifferentFilesOfSamePackage(KOTLIN_1_5),
SealedInterfaces(KOTLIN_1_5), SealedInterfaces(KOTLIN_1_5),
JvmIrEnabledByDefault(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: * Improvements include the following: