diff --git a/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesSerializerExtension.kt b/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesSerializerExtension.kt index c1a6a665c42..061a964d9c4 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesSerializerExtension.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesSerializerExtension.kt @@ -55,10 +55,13 @@ class JavaClassesSerializerExtension : KotlinSerializerExtensionBase(BuiltInSeri } } - override fun serializeFunction(descriptor: FunctionDescriptor, - proto: ProtoBuf.Function.Builder, - childSerializer: DescriptorSerializer) { - super.serializeFunction(descriptor, proto, childSerializer) + override fun serializeFunction( + descriptor: FunctionDescriptor, + proto: ProtoBuf.Function.Builder, + versionRequirementTable: MutableVersionRequirementTable?, + childSerializer: DescriptorSerializer + ) { + super.serializeFunction(descriptor, proto, versionRequirementTable, childSerializer) if (descriptor.visibility == JavaVisibilities.PACKAGE_VISIBILITY) { proto.setExtension(JavaClassProtoBuf.isPackagePrivateMethod, true) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt index 428e6882145..fc7c915ca38 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmSerializerExtension.kt @@ -5,11 +5,13 @@ package org.jetbrains.kotlin.codegen.serialization +import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.codegen.ClassBuilderMode import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.createFreeFakeLocalPropertyDescriptor import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.* import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.load.java.JvmAbi @@ -45,7 +47,8 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta private val useTypeTable = state.useTypeTableInSerializer private val moduleName = state.moduleName private val classBuilderMode = state.classBuilderMode - private val isReleaseCoroutines = state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) + private val languageVersionSettings = state.languageVersionSettings + private val isParamAssertionsDisabled = state.isParamAssertionsDisabled override val metadataVersion = state.metadataVersion override fun shouldUseTypeTable(): Boolean = useTypeTable @@ -165,7 +168,10 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta } override fun serializeFunction( - descriptor: FunctionDescriptor, proto: ProtoBuf.Function.Builder, childSerializer: DescriptorSerializer + descriptor: FunctionDescriptor, + proto: ProtoBuf.Function.Builder, + versionRequirementTable: MutableVersionRequirementTable?, + childSerializer: DescriptorSerializer ) { val method = getBinding(METHOD_FOR_FUNCTION, descriptor) if (method != null) { @@ -174,8 +180,25 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta proto.setExtension(JvmProtoBuf.methodSignature, signature) } } + + if (descriptor.needsInlineParameterNullCheckRequirement()) { + versionRequirementTable?.writeInlineParameterNullCheckRequirement(proto::addVersionRequirement) + } } + private fun MutableVersionRequirementTable.writeInlineParameterNullCheckRequirement(add: (Int) -> Unit) { + if (languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4) { + // Since Kotlin 1.4, we generate a call to Intrinsics.checkNotNullParameter in inline functions which causes older compilers + // (earlier than 1.3.50) to crash because a functional parameter in this position can't be inlined + add(writeVersionRequirement(1, 3, 50, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, this)) + } + } + + private fun FunctionDescriptor.needsInlineParameterNullCheckRequirement(): Boolean = + isInline && !isSuspend && !isParamAssertionsDisabled && + !Visibilities.isPrivate(visibility) && + (valueParameters.any { it.type.isFunctionType } || extensionReceiverParameter?.type?.isFunctionType == true) + override fun serializeProperty( descriptor: PropertyDescriptor, proto: ProtoBuf.Property.Builder, @@ -212,6 +235,10 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta writeVersionRequirement(1, 2, 70, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable) ) } + + if (getter?.needsInlineParameterNullCheckRequirement() == true || setter?.needsInlineParameterNullCheckRequirement() == true) { + versionRequirementTable?.writeInlineParameterNullCheckRequirement(proto::addVersionRequirement) + } } private fun PropertyDescriptor.isJvmFieldPropertyInInterfaceCompanion(): Boolean { @@ -329,6 +356,6 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta } override fun releaseCoroutines(): Boolean { - return isReleaseCoroutines + return languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) } } diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/JsKlibMetadataSerializerExtension.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/JsKlibMetadataSerializerExtension.kt index 93071843b5c..3888ba0abde 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/JsKlibMetadataSerializerExtension.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/metadata/JsKlibMetadataSerializerExtension.kt @@ -91,16 +91,18 @@ class JsKlibMetadataSerializerExtension( super.serializeProperty(descriptor, proto, versionRequirementTable, childSerializer) } - override fun serializeFunction(descriptor: FunctionDescriptor, - proto: ProtoBuf.Function.Builder, - childSerializer: DescriptorSerializer + override fun serializeFunction( + descriptor: FunctionDescriptor, + proto: ProtoBuf.Function.Builder, + versionRequirementTable: MutableVersionRequirementTable?, + childSerializer: DescriptorSerializer ) { uniqId(descriptor)?.let { proto.setExtension(JsKlibMetadataProtoBuf.functionUniqId, it) } val id = getFileId(descriptor) if (id != null) { proto.setExtension(JsKlibMetadataProtoBuf.functionContainingFileId, id) } - super.serializeFunction(descriptor, proto, childSerializer) + super.serializeFunction(descriptor, proto, versionRequirementTable, childSerializer) } private fun getFileId(descriptor: DeclarationDescriptor): Int? { diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt index f8adc936978..076a658c155 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt @@ -353,7 +353,7 @@ class DescriptorSerializer private constructor( contractSerializer.serializeContractOfFunctionIfAny(descriptor, builder, this) - extension.serializeFunction(descriptor, builder, local) + extension.serializeFunction(descriptor, builder, versionRequirementTable, local) return builder } diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.kt index b5fc8131916..3b8c8176d65 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.kt @@ -56,6 +56,7 @@ abstract class SerializerExtension { open fun serializeFunction( descriptor: FunctionDescriptor, proto: ProtoBuf.Function.Builder, + versionRequirementTable: MutableVersionRequirementTable?, childSerializer: DescriptorSerializer ) { } diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtensionBase.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtensionBase.kt index 8a364ae22e6..881c5ab5314 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtensionBase.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtensionBase.kt @@ -55,6 +55,7 @@ abstract class KotlinSerializerExtensionBase(private val protocol: SerializerExt override fun serializeFunction( descriptor: FunctionDescriptor, proto: ProtoBuf.Function.Builder, + versionRequirementTable: MutableVersionRequirementTable?, childSerializer: DescriptorSerializer ) { for (annotation in descriptor.nonSourceAnnotations) { diff --git a/compiler/testData/versionRequirement/inlineParameterNullCheck.kt b/compiler/testData/versionRequirement/inlineParameterNullCheck.kt new file mode 100644 index 00000000000..ad3611aa689 --- /dev/null +++ b/compiler/testData/versionRequirement/inlineParameterNullCheck.kt @@ -0,0 +1,13 @@ +package test + +inline fun doRun(f: () -> Unit) {} + +// Note that although lambdas are not inlined in property accessors (neither in setter parameter, nor in extension receiver parameter), +// we still generate version requirements, just in case we support inlining here in the future. +inline var lambdaVarProperty: () -> Unit + get() = {} + set(value) { value() } + +inline var (() -> String).extensionProperty: String + get() = this() + set(value) { this() } diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt b/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt index b00e3b745bc..f7862ee33a7 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/serialization/JvmVersionRequirementTest.kt @@ -40,7 +40,10 @@ class JvmVersionRequirementTest : AbstractVersionRequirementTest() { languageVersionSettings = LanguageVersionSettingsImpl( languageVersion, ApiVersion.createByLanguageVersion(languageVersion), - mapOf(JvmAnalysisFlags.jvmDefaultMode to JvmDefaultMode.ENABLE), + mapOf( + JvmAnalysisFlags.jvmDefaultMode to JvmDefaultMode.ENABLE, + AnalysisFlags.explicitApiVersion to true + ), emptyMap() ) }, @@ -73,4 +76,16 @@ class JvmVersionRequirementTest : AbstractVersionRequirementTest() { fqNames = listOf("test.Base.Companion.foo") ) } + + fun testInlineParameterNullCheck() { + doTest( + VersionRequirement.Version(1, 3, 50), DeprecationLevel.ERROR, null, COMPILER_VERSION, null, + fqNames = listOf( + "test.doRun", + "test.lambdaVarProperty", + "test.extensionProperty" + ), + customLanguageVersion = LanguageVersion.KOTLIN_1_4 + ) + } } diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt index 6bf41ab136f..8b27bec57fc 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt @@ -67,14 +67,17 @@ class KotlinJavascriptSerializerExtension( super.serializeProperty(descriptor, proto, versionRequirementTable, childSerializer) } - override fun serializeFunction(descriptor: FunctionDescriptor, - proto: ProtoBuf.Function.Builder, - childSerializer: DescriptorSerializer) { + override fun serializeFunction( + descriptor: FunctionDescriptor, + proto: ProtoBuf.Function.Builder, + versionRequirementTable: MutableVersionRequirementTable?, + childSerializer: DescriptorSerializer + ) { val id = getFileId(descriptor) if (id != null) { proto.setExtension(JsProtoBuf.functionContainingFileId, id) } - super.serializeFunction(descriptor, proto, childSerializer) + super.serializeFunction(descriptor, proto, versionRequirementTable, childSerializer) } private fun getFileId(descriptor: DeclarationDescriptor): Int? {