Metadata: 'non-stable parameter names' flag for callables
^KT-34602
This commit is contained in:
+4
-2
@@ -310,7 +310,8 @@ class FirElementSerializer private constructor(
|
|||||||
simpleFunction?.isTailRec == true,
|
simpleFunction?.isTailRec == true,
|
||||||
simpleFunction?.isExternal == true,
|
simpleFunction?.isExternal == true,
|
||||||
simpleFunction?.isSuspend == true,
|
simpleFunction?.isSuspend == true,
|
||||||
simpleFunction?.isExpect == true
|
simpleFunction?.isExpect == true,
|
||||||
|
true // TODO: supply 'hasStableParameterNames' flag for metadata
|
||||||
)
|
)
|
||||||
if (flags != builder.flags) {
|
if (flags != builder.flags) {
|
||||||
builder.flags = flags
|
builder.flags = flags
|
||||||
@@ -439,7 +440,8 @@ class FirElementSerializer private constructor(
|
|||||||
val flags = Flags.getConstructorFlags(
|
val flags = Flags.getConstructorFlags(
|
||||||
constructor.nonSourceAnnotations(session).isNotEmpty(),
|
constructor.nonSourceAnnotations(session).isNotEmpty(),
|
||||||
ProtoEnumFlags.visibility(normalizeVisibility(constructor)),
|
ProtoEnumFlags.visibility(normalizeVisibility(constructor)),
|
||||||
!constructor.isPrimary
|
!constructor.isPrimary,
|
||||||
|
true // TODO: supply 'hasStableParameterNames' flag for metadata
|
||||||
)
|
)
|
||||||
if (flags != builder.flags) {
|
if (flags != builder.flags) {
|
||||||
builder.flags = flags
|
builder.flags = flags
|
||||||
|
|||||||
+3
-1
@@ -264,7 +264,9 @@ private class FirCallArgumentsProcessor(private val function: FirFunction<*>) {
|
|||||||
private val FirExpression.argumentName: Name?
|
private val FirExpression.argumentName: Name?
|
||||||
get() = (this as? FirNamedArgumentExpression)?.name
|
get() = (this as? FirNamedArgumentExpression)?.name
|
||||||
|
|
||||||
// TODO: handle java functions
|
// TODO: handle functions with non-stable parameter names, see also
|
||||||
|
// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.functionProto
|
||||||
|
// org.jetbrains.kotlin.fir.serialization.FirElementSerializer.constructorProto
|
||||||
private val FirFunction<*>.hasStableParameterNames: Boolean
|
private val FirFunction<*>.hasStableParameterNames: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -74,10 +74,10 @@ inline class FunctionFlags(val flags: Long) {
|
|||||||
val modality = ProtoEnumFlags.modality(modality)
|
val modality = ProtoEnumFlags.modality(modality)
|
||||||
val kind = if (isFakeOverride) ProtoBuf.MemberKind.FAKE_OVERRIDE else ProtoBuf.MemberKind.DECLARATION
|
val kind = if (isFakeOverride) ProtoBuf.MemberKind.FAKE_OVERRIDE else ProtoBuf.MemberKind.DECLARATION
|
||||||
|
|
||||||
|
|
||||||
val flags = IrFlags.getFunctionFlags(
|
val flags = IrFlags.getFunctionFlags(
|
||||||
hasAnnotation, visibility, modality, kind,
|
hasAnnotation, visibility, modality, kind,
|
||||||
isOperator, isInfix, isInline, isTailrec, isExternal, isSuspend, isExpect
|
isOperator, isInfix, isInline, isTailrec, isExternal, isSuspend, isExpect,
|
||||||
|
true // hasStableParameterNames does not make sense for Ir, just pass the default value
|
||||||
)
|
)
|
||||||
|
|
||||||
return flags.toLong()
|
return flags.toLong()
|
||||||
|
|||||||
+11
-2
@@ -291,6 +291,14 @@ class DescriptorSerializer private constructor(
|
|||||||
else
|
else
|
||||||
descriptor.visibility
|
descriptor.visibility
|
||||||
|
|
||||||
|
private fun shouldSerializeHasStableParameterNames(descriptor: CallableMemberDescriptor): Boolean {
|
||||||
|
return when {
|
||||||
|
descriptor.hasStableParameterNames() -> true
|
||||||
|
descriptor.kind == CallableMemberDescriptor.Kind.DELEGATION -> true // remove this line to fix KT-4758
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun functionProto(descriptor: FunctionDescriptor): ProtoBuf.Function.Builder? {
|
fun functionProto(descriptor: FunctionDescriptor): ProtoBuf.Function.Builder? {
|
||||||
if (!extension.shouldSerializeFunction(descriptor)) return null
|
if (!extension.shouldSerializeFunction(descriptor)) return null
|
||||||
|
|
||||||
@@ -304,7 +312,7 @@ class DescriptorSerializer private constructor(
|
|||||||
ProtoEnumFlags.modality(descriptor.modality),
|
ProtoEnumFlags.modality(descriptor.modality),
|
||||||
ProtoEnumFlags.memberKind(descriptor.kind),
|
ProtoEnumFlags.memberKind(descriptor.kind),
|
||||||
descriptor.isOperator, descriptor.isInfix, descriptor.isInline, descriptor.isTailrec, descriptor.isExternal,
|
descriptor.isOperator, descriptor.isInfix, descriptor.isInline, descriptor.isTailrec, descriptor.isExternal,
|
||||||
descriptor.isSuspend, descriptor.isExpect
|
descriptor.isSuspend, descriptor.isExpect, shouldSerializeHasStableParameterNames(descriptor)
|
||||||
)
|
)
|
||||||
if (flags != builder.flags) {
|
if (flags != builder.flags) {
|
||||||
builder.flags = flags
|
builder.flags = flags
|
||||||
@@ -367,7 +375,8 @@ class DescriptorSerializer private constructor(
|
|||||||
val local = createChildSerializer(descriptor)
|
val local = createChildSerializer(descriptor)
|
||||||
|
|
||||||
val flags = Flags.getConstructorFlags(
|
val flags = Flags.getConstructorFlags(
|
||||||
hasAnnotations(descriptor), ProtoEnumFlags.visibility(normalizeVisibility(descriptor)), !descriptor.isPrimary
|
hasAnnotations(descriptor), ProtoEnumFlags.visibility(normalizeVisibility(descriptor)), !descriptor.isPrimary,
|
||||||
|
shouldSerializeHasStableParameterNames(descriptor)
|
||||||
)
|
)
|
||||||
if (flags != builder.flags) {
|
if (flags != builder.flags) {
|
||||||
builder.flags = flags
|
builder.flags = flags
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package library
|
||||||
|
|
||||||
|
fun foo(a: Int, b: String, c: Boolean) = Unit
|
||||||
|
|
||||||
|
class Foo(a: Int, b: String, c: Boolean) {
|
||||||
|
constructor(a: Int, b: String, c: Boolean, d: Double) : this(a, b, c)
|
||||||
|
|
||||||
|
fun foo(a: Int, b: String, c: Boolean) = Unit
|
||||||
|
|
||||||
|
class Bar(a: Int, b: String, c: Boolean) {
|
||||||
|
constructor(a: Int, b: String, c: Boolean, d: Double) : this(a, b, c)
|
||||||
|
|
||||||
|
fun bar(a: Int, b: String, c: Boolean) = Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataMonolithicSerializer
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||||
|
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||||
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||||
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
|
||||||
|
import org.jetbrains.kotlin.library.*
|
||||||
|
import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
|
||||||
|
import org.jetbrains.kotlin.library.impl.KotlinLibraryWriterImpl
|
||||||
|
import org.jetbrains.kotlin.library.metadata.NativeTypeTransformer
|
||||||
|
import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||||
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
|
import org.jetbrains.kotlin.util.DummyLogger
|
||||||
|
import java.io.File
|
||||||
|
import org.jetbrains.kotlin.konan.file.File as KFile
|
||||||
|
|
||||||
|
object KlibTestUtil {
|
||||||
|
fun compileCommonSourcesToKlib(sourceFiles: Collection<File>, libraryName: String, klibFile: File) {
|
||||||
|
require(!Name.guessByFirstCharacter(libraryName).isSpecial) { "Invalid library name: $libraryName" }
|
||||||
|
|
||||||
|
val configuration = KotlinTestUtils.newConfiguration()
|
||||||
|
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
|
||||||
|
configuration.put(CommonConfigurationKeys.MODULE_NAME, libraryName)
|
||||||
|
configuration.addKotlinSourceRoots(sourceFiles.map { it.absolutePath })
|
||||||
|
|
||||||
|
val rootDisposable = Disposer.newDisposable()
|
||||||
|
val module = try {
|
||||||
|
val environment = KotlinCoreEnvironment.createForTests(
|
||||||
|
parentDisposable = rootDisposable,
|
||||||
|
initialConfiguration = configuration,
|
||||||
|
extensionConfigs = EnvironmentConfigFiles.METADATA_CONFIG_FILES
|
||||||
|
)
|
||||||
|
|
||||||
|
CommonResolverForModuleFactory.analyzeFiles(
|
||||||
|
files = environment.getSourceFiles(),
|
||||||
|
moduleName = Name.special("<$libraryName>"),
|
||||||
|
dependOnBuiltIns = true,
|
||||||
|
languageVersionSettings = environment.configuration.languageVersionSettings,
|
||||||
|
targetPlatform = CommonPlatforms.defaultCommonPlatform
|
||||||
|
) { content ->
|
||||||
|
environment.createPackagePartProvider(content.moduleContentScope)
|
||||||
|
}.moduleDescriptor
|
||||||
|
} finally {
|
||||||
|
Disposer.dispose(rootDisposable)
|
||||||
|
}
|
||||||
|
|
||||||
|
serializeCommonModuleToKlib(module, libraryName, klibFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun serializeCommonModuleToKlib(module: ModuleDescriptor, libraryName: String, klibFile: File) {
|
||||||
|
require(klibFile.extension == KLIB_FILE_EXTENSION) { "KLIB file must have $KLIB_FILE_EXTENSION extension" }
|
||||||
|
|
||||||
|
val serializer = KlibMetadataMonolithicSerializer(
|
||||||
|
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
|
||||||
|
metadataVersion = KlibMetadataVersion.INSTANCE,
|
||||||
|
skipExpects = false
|
||||||
|
)
|
||||||
|
|
||||||
|
val serializedMetadata = serializer.serializeModule(module)
|
||||||
|
|
||||||
|
val library = KotlinLibraryWriterImpl(
|
||||||
|
libDir = KFile(klibFile.path.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT)),
|
||||||
|
moduleName = libraryName,
|
||||||
|
versions = KotlinLibraryVersioning(
|
||||||
|
libraryVersion = null,
|
||||||
|
compilerVersion = null,
|
||||||
|
abiVersion = null,
|
||||||
|
metadataVersion = KlibMetadataVersion.INSTANCE.toString(),
|
||||||
|
irVersion = null
|
||||||
|
),
|
||||||
|
builtInsPlatform = BuiltInsPlatform.COMMON,
|
||||||
|
nativeTargets = emptyList(),
|
||||||
|
nopack = false,
|
||||||
|
shortName = libraryName
|
||||||
|
)
|
||||||
|
|
||||||
|
library.addMetadata(serializedMetadata)
|
||||||
|
library.commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deserializeKlibToCommonModule(klibFile: File): ModuleDescriptorImpl {
|
||||||
|
val library = resolveSingleFileKlib(
|
||||||
|
libraryFile = KFile(klibFile.path),
|
||||||
|
logger = DummyLogger,
|
||||||
|
strategy = ToolingSingleFileKlibResolveStrategy
|
||||||
|
)
|
||||||
|
|
||||||
|
val metadataFactories = KlibMetadataFactories({ DefaultBuiltIns.Instance }, NullFlexibleTypeDeserializer, NativeTypeTransformer())
|
||||||
|
|
||||||
|
val module = metadataFactories.DefaultDeserializedDescriptorFactory.createDescriptor(
|
||||||
|
library = library,
|
||||||
|
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
|
||||||
|
storageManager = LockBasedStorageManager.NO_LOCKS,
|
||||||
|
builtIns = DefaultBuiltIns.Instance,
|
||||||
|
packageAccessHandler = null
|
||||||
|
)
|
||||||
|
module.setDependencies(listOf(DefaultBuiltIns.Instance.builtInsModule, module))
|
||||||
|
|
||||||
|
return module
|
||||||
|
}
|
||||||
|
}
|
||||||
+105
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.serialization
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter.Companion.CLASSIFIERS_MASK
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter.Companion.FUNCTIONS_MASK
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
|
import org.jetbrains.kotlin.test.KlibTestUtil
|
||||||
|
import org.jetbrains.kotlin.test.TestCaseWithTmpdir
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
||||||
|
import org.jetbrains.kotlin.utils.alwaysTrue
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class NonStableParameterNamesSerializationTest : TestCaseWithTmpdir() {
|
||||||
|
fun testNonStableParameterNames() {
|
||||||
|
val originalKlibName = File(SOURCE_FILE).nameWithoutExtension
|
||||||
|
val originalKlibFile = File(tmpdir, "$originalKlibName.klib")
|
||||||
|
KlibTestUtil.compileCommonSourcesToKlib(listOf(File(SOURCE_FILE)), originalKlibName, originalKlibFile)
|
||||||
|
|
||||||
|
val originalModule = KlibTestUtil.deserializeKlibToCommonModule(originalKlibFile)
|
||||||
|
val originalCallables = collectCallablesForPatch(originalModule)
|
||||||
|
|
||||||
|
assertTrue { originalCallables.isNotEmpty() }
|
||||||
|
assertTrue { originalCallables.all { it.hasStableParameterNames() } }
|
||||||
|
|
||||||
|
originalCallables.forEach { it.setHasStableParameterNames(false) }
|
||||||
|
|
||||||
|
val patchedKlibName = "${originalKlibFile.nameWithoutExtension}-patched"
|
||||||
|
val patchedKlibFile = originalKlibFile.resolveSibling("$patchedKlibName.klib")
|
||||||
|
KlibTestUtil.serializeCommonModuleToKlib(originalModule, patchedKlibName, patchedKlibFile)
|
||||||
|
|
||||||
|
val patchedModule = KlibTestUtil.deserializeKlibToCommonModule(patchedKlibFile)
|
||||||
|
val patchedCallables = collectCallablesForPatch(patchedModule)
|
||||||
|
|
||||||
|
assertEquals(expected = originalCallables.size, actual = patchedCallables.size)
|
||||||
|
assertEquals(expected = originalCallables.map { it.signature }.toSet(), actual = patchedCallables.map { it.signature }.toSet())
|
||||||
|
assertTrue { patchedCallables.all { !it.hasStableParameterNames() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SOURCE_FILE = "compiler/testData/serialization/nonStableParameterNames/test.kt"
|
||||||
|
|
||||||
|
private fun collectCallablesForPatch(module: ModuleDescriptorImpl): List<FunctionDescriptorImpl> {
|
||||||
|
fun DeclarationDescriptor.castToFunctionImpl(): FunctionDescriptorImpl =
|
||||||
|
assertedCast { "Not an instance of ${FunctionDescriptorImpl::class.java}: ${this::class.java}, $this" }
|
||||||
|
|
||||||
|
val result = mutableListOf<FunctionDescriptorImpl>()
|
||||||
|
|
||||||
|
fun recurse(memberScope: MemberScope) {
|
||||||
|
memberScope
|
||||||
|
.getContributedDescriptors(DescriptorKindFilter(FUNCTIONS_MASK or CLASSIFIERS_MASK))
|
||||||
|
.forEach { descriptor ->
|
||||||
|
when (descriptor) {
|
||||||
|
is SimpleFunctionDescriptor -> {
|
||||||
|
if (descriptor.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
|
||||||
|
result += descriptor.castToFunctionImpl()
|
||||||
|
}
|
||||||
|
is ClassDescriptor -> {
|
||||||
|
descriptor.constructors.mapTo(result) { it.castToFunctionImpl() }
|
||||||
|
recurse(descriptor.unsubstitutedMemberScope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val packageFragmentProvider = module.packageFragmentProviderForModuleContentWithoutDependencies
|
||||||
|
|
||||||
|
fun recurse(packageFqName: FqName) {
|
||||||
|
packageFragmentProvider
|
||||||
|
.getPackageFragments(packageFqName)
|
||||||
|
.forEach { packageFragment ->
|
||||||
|
recurse(packageFragment.getMemberScope())
|
||||||
|
}
|
||||||
|
|
||||||
|
packageFragmentProvider
|
||||||
|
.getSubPackagesOf(packageFqName, alwaysTrue())
|
||||||
|
.toSet()
|
||||||
|
.forEach { recurse(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
recurse(FqName.ROOT)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private val FunctionDescriptorImpl.signature: String
|
||||||
|
get() = buildString {
|
||||||
|
append(fqNameSafe)
|
||||||
|
append('(')
|
||||||
|
valueParameters.joinTo(this, ",") { it.type.constructor.declarationDescriptor?.fqNameSafe?.asString().orEmpty() }
|
||||||
|
append(')')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -15,7 +15,7 @@ class KlibMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
@JvmField
|
||||||
val INSTANCE = KlibMetadataVersion(1, 4, 0)
|
val INSTANCE = KlibMetadataVersion(1, 4, 1)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val INVALID_VERSION = KlibMetadataVersion()
|
val INVALID_VERSION = KlibMetadataVersion()
|
||||||
|
|||||||
+5
@@ -272,6 +272,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
|||||||
ProtoEnumFlags.memberKind(Flags.MEMBER_KIND.get(flags)), proto, c.nameResolver, c.typeTable, versionRequirementTable,
|
ProtoEnumFlags.memberKind(Flags.MEMBER_KIND.get(flags)), proto, c.nameResolver, c.typeTable, versionRequirementTable,
|
||||||
c.containerSource
|
c.containerSource
|
||||||
)
|
)
|
||||||
|
|
||||||
val local = c.childContext(function, proto.typeParameterList)
|
val local = c.childContext(function, proto.typeParameterList)
|
||||||
|
|
||||||
function.initializeWithCoroutinesExperimentalityStatus(
|
function.initializeWithCoroutinesExperimentalityStatus(
|
||||||
@@ -294,6 +295,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
|||||||
function.isTailrec = Flags.IS_TAILREC.get(flags)
|
function.isTailrec = Flags.IS_TAILREC.get(flags)
|
||||||
function.isSuspend = Flags.IS_SUSPEND.get(flags)
|
function.isSuspend = Flags.IS_SUSPEND.get(flags)
|
||||||
function.isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
|
function.isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
|
||||||
|
function.setHasStableParameterNames(!Flags.IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES.get(flags))
|
||||||
|
|
||||||
val mapValueForContract =
|
val mapValueForContract =
|
||||||
c.components.contractDeserializer.deserializeContractFromFunction(proto, function, c.typeTable, local.typeDeserializer)
|
c.components.contractDeserializer.deserializeContractFromFunction(proto, function, c.typeTable, local.typeDeserializer)
|
||||||
@@ -337,6 +339,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
|||||||
isPrimary, CallableMemberDescriptor.Kind.DECLARATION, proto, c.nameResolver, c.typeTable, c.versionRequirementTable,
|
isPrimary, CallableMemberDescriptor.Kind.DECLARATION, proto, c.nameResolver, c.typeTable, c.versionRequirementTable,
|
||||||
c.containerSource
|
c.containerSource
|
||||||
)
|
)
|
||||||
|
|
||||||
val local = c.childContext(descriptor, listOf())
|
val local = c.childContext(descriptor, listOf())
|
||||||
descriptor.initialize(
|
descriptor.initialize(
|
||||||
local.memberDeserializer.valueParameters(proto.valueParameterList, proto, AnnotatedCallableKind.FUNCTION),
|
local.memberDeserializer.valueParameters(proto.valueParameterList, proto, AnnotatedCallableKind.FUNCTION),
|
||||||
@@ -344,6 +347,8 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
|||||||
)
|
)
|
||||||
descriptor.returnType = classDescriptor.defaultType
|
descriptor.returnType = classDescriptor.defaultType
|
||||||
|
|
||||||
|
descriptor.setHasStableParameterNames(!Flags.IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES.get(proto.flags))
|
||||||
|
|
||||||
val doesClassContainIncompatibility =
|
val doesClassContainIncompatibility =
|
||||||
(c.containingDeclaration as? DeserializedClassDescriptor)
|
(c.containingDeclaration as? DeserializedClassDescriptor)
|
||||||
?.c?.typeDeserializer?.experimentalSuspendFunctionTypeEncountered == true
|
?.c?.typeDeserializer?.experimentalSuspendFunctionTypeEncountered == true
|
||||||
|
|||||||
+5
-1
@@ -120,6 +120,7 @@ class DeserializedSimpleFunctionDescriptor(
|
|||||||
newOwner, original as SimpleFunctionDescriptor?, annotations, newName ?: name, kind,
|
newOwner, original as SimpleFunctionDescriptor?, annotations, newName ?: name, kind,
|
||||||
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source
|
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source
|
||||||
).also {
|
).also {
|
||||||
|
it.setHasStableParameterNames(hasStableParameterNames())
|
||||||
it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode
|
it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,7 +210,10 @@ class DeserializedClassConstructorDescriptor(
|
|||||||
return DeserializedClassConstructorDescriptor(
|
return DeserializedClassConstructorDescriptor(
|
||||||
newOwner as ClassDescriptor, original as ConstructorDescriptor?, annotations, isPrimary, kind,
|
newOwner as ClassDescriptor, original as ConstructorDescriptor?, annotations, isPrimary, kind,
|
||||||
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source
|
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source
|
||||||
).also { it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode }
|
).also {
|
||||||
|
it.setHasStableParameterNames(hasStableParameterNames())
|
||||||
|
it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isExternal(): Boolean = false
|
override fun isExternal(): Boolean = false
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ class JvmMetadataVersion(versionArray: IntArray, val isStrictSemantics: Boolean)
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
@JvmField
|
||||||
val INSTANCE = JvmMetadataVersion(1, 4, 0)
|
val INSTANCE = JvmMetadataVersion(1, 4, 1)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val INVALID_VERSION = JvmMetadataVersion()
|
val INVALID_VERSION = JvmMetadataVersion()
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ message Constructor {
|
|||||||
hasAnnotations
|
hasAnnotations
|
||||||
Visibility
|
Visibility
|
||||||
isSecondary
|
isSecondary
|
||||||
|
hasNonStableParameterNames
|
||||||
*/
|
*/
|
||||||
optional int32 flags = 1 [default = 6 /* public constructor, no annotations */];
|
optional int32 flags = 1 [default = 6 /* public constructor, no annotations */];
|
||||||
|
|
||||||
@@ -294,6 +295,7 @@ message Function {
|
|||||||
isExternal
|
isExternal
|
||||||
isSuspend
|
isSuspend
|
||||||
isExpect
|
isExpect
|
||||||
|
hasNonStableParameterNames
|
||||||
*/
|
*/
|
||||||
optional int32 flags = 9 [default = 6 /* public final function, no annotations */];
|
optional int32 flags = 9 [default = 6 /* public final function, no annotations */];
|
||||||
optional int32 old_flags = 1 [default = 6];
|
optional int32 old_flags = 1 [default = 6];
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public class Flags {
|
|||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
public static final BooleanFlagField IS_SECONDARY = FlagField.booleanAfter(VISIBILITY);
|
public static final BooleanFlagField IS_SECONDARY = FlagField.booleanAfter(VISIBILITY);
|
||||||
|
public static final BooleanFlagField IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES = FlagField.booleanAfter(IS_SECONDARY);
|
||||||
|
|
||||||
// Callables
|
// Callables
|
||||||
|
|
||||||
@@ -49,6 +50,7 @@ public class Flags {
|
|||||||
public static final BooleanFlagField IS_EXTERNAL_FUNCTION = FlagField.booleanAfter(IS_TAILREC);
|
public static final BooleanFlagField IS_EXTERNAL_FUNCTION = FlagField.booleanAfter(IS_TAILREC);
|
||||||
public static final BooleanFlagField IS_SUSPEND = FlagField.booleanAfter(IS_EXTERNAL_FUNCTION);
|
public static final BooleanFlagField IS_SUSPEND = FlagField.booleanAfter(IS_EXTERNAL_FUNCTION);
|
||||||
public static final BooleanFlagField IS_EXPECT_FUNCTION = FlagField.booleanAfter(IS_SUSPEND);
|
public static final BooleanFlagField IS_EXPECT_FUNCTION = FlagField.booleanAfter(IS_SUSPEND);
|
||||||
|
public static final BooleanFlagField IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES = FlagField.booleanAfter(IS_EXPECT_FUNCTION);
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
|
|
||||||
@@ -115,11 +117,13 @@ public class Flags {
|
|||||||
public static int getConstructorFlags(
|
public static int getConstructorFlags(
|
||||||
boolean hasAnnotations,
|
boolean hasAnnotations,
|
||||||
@NotNull ProtoBuf.Visibility visibility,
|
@NotNull ProtoBuf.Visibility visibility,
|
||||||
boolean isSecondary
|
boolean isSecondary,
|
||||||
|
boolean hasStableParameterNames
|
||||||
) {
|
) {
|
||||||
return HAS_ANNOTATIONS.toFlags(hasAnnotations)
|
return HAS_ANNOTATIONS.toFlags(hasAnnotations)
|
||||||
| VISIBILITY.toFlags(visibility)
|
| VISIBILITY.toFlags(visibility)
|
||||||
| IS_SECONDARY.toFlags(isSecondary)
|
| IS_SECONDARY.toFlags(isSecondary)
|
||||||
|
| IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES.toFlags(!hasStableParameterNames)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +138,8 @@ public class Flags {
|
|||||||
boolean isTailrec,
|
boolean isTailrec,
|
||||||
boolean isExternal,
|
boolean isExternal,
|
||||||
boolean isSuspend,
|
boolean isSuspend,
|
||||||
boolean isExpect
|
boolean isExpect,
|
||||||
|
boolean hasStableParameterNames
|
||||||
) {
|
) {
|
||||||
return HAS_ANNOTATIONS.toFlags(hasAnnotations)
|
return HAS_ANNOTATIONS.toFlags(hasAnnotations)
|
||||||
| VISIBILITY.toFlags(visibility)
|
| VISIBILITY.toFlags(visibility)
|
||||||
@@ -147,6 +152,7 @@ public class Flags {
|
|||||||
| IS_EXTERNAL_FUNCTION.toFlags(isExternal)
|
| IS_EXTERNAL_FUNCTION.toFlags(isExternal)
|
||||||
| IS_SUSPEND.toFlags(isSuspend)
|
| IS_SUSPEND.toFlags(isSuspend)
|
||||||
| IS_EXPECT_FUNCTION.toFlags(isExpect)
|
| IS_EXPECT_FUNCTION.toFlags(isExpect)
|
||||||
|
| IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES.toFlags(!hasStableParameterNames)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import kotlinx.metadata.*
|
|||||||
import kotlinx.metadata.jvm.*
|
import kotlinx.metadata.jvm.*
|
||||||
import org.jetbrains.org.objectweb.asm.ClassWriter
|
import org.jetbrains.org.objectweb.asm.ClassWriter
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@@ -169,4 +169,38 @@ class MetadataSmokeTest {
|
|||||||
) as KotlinClassMetadata.SyntheticClass
|
) as KotlinClassMetadata.SyntheticClass
|
||||||
metadata.accept(KmLambda())
|
metadata.accept(KmLambda())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unstableParameterNames() {
|
||||||
|
@Suppress("unused")
|
||||||
|
class Test(a: String, b: Int, c: Boolean) {
|
||||||
|
fun foo(a: String, b: Int, c: Boolean) = Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
val classWithStableParameterNames =
|
||||||
|
(KotlinClassMetadata.read(Test::class.java.readMetadata()) as KotlinClassMetadata.Class).toKmClass()
|
||||||
|
|
||||||
|
classWithStableParameterNames.constructors.forEach { assertFalse(Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) }
|
||||||
|
classWithStableParameterNames.functions.forEach { assertFalse(Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) }
|
||||||
|
|
||||||
|
val newMetadata = KotlinClassMetadata.Class.Writer().let { writer ->
|
||||||
|
KmClass().apply {
|
||||||
|
classWithStableParameterNames.accept(
|
||||||
|
object : KmClassVisitor(this) {
|
||||||
|
override fun visitConstructor(flags: Flags) =
|
||||||
|
super.visitConstructor(flags + flagsOf(Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES))
|
||||||
|
|
||||||
|
override fun visitFunction(flags: Flags, name: String) =
|
||||||
|
super.visitFunction(flags + flagsOf(Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES), name)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.accept(writer)
|
||||||
|
writer.write()
|
||||||
|
}
|
||||||
|
|
||||||
|
val classWithUnstableParameterNames = newMetadata.toKmClass()
|
||||||
|
|
||||||
|
classWithUnstableParameterNames.constructors.forEach { assertTrue(Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) }
|
||||||
|
classWithUnstableParameterNames.functions.forEach { assertTrue(Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES(it.flags)) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,6 +224,12 @@ class Flag(private val offset: Int, private val bitWidth: Int, private val value
|
|||||||
*/
|
*/
|
||||||
@JvmField
|
@JvmField
|
||||||
val IS_PRIMARY = Flag(F.IS_SECONDARY, 0)
|
val IS_PRIMARY = Flag(F.IS_SECONDARY, 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signifies that the corresponding constructor has non-stable parameter names, i.e. cannot be called with named arguments.
|
||||||
|
*/
|
||||||
|
@JvmField
|
||||||
|
val HAS_NON_STABLE_PARAMETER_NAMES = Flag(F.IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -302,6 +308,12 @@ class Flag(private val offset: Int, private val bitWidth: Int, private val value
|
|||||||
*/
|
*/
|
||||||
@JvmField
|
@JvmField
|
||||||
val IS_EXPECT = Flag(F.IS_EXPECT_FUNCTION)
|
val IS_EXPECT = Flag(F.IS_EXPECT_FUNCTION)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signifies that the corresponding function has non-stable parameter names, i.e. cannot be called with named arguments.
|
||||||
|
*/
|
||||||
|
@JvmField
|
||||||
|
val HAS_NON_STABLE_PARAMETER_NAMES = Flag(F.IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -958,7 +958,8 @@ private val CLASS_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val CONSTRUCTOR_FLAGS_MAP = VISIBILITY_FLAGS_MAP + mapOf(
|
private val CONSTRUCTOR_FLAGS_MAP = VISIBILITY_FLAGS_MAP + mapOf(
|
||||||
Flag.Constructor.IS_PRIMARY to "/* primary */"
|
Flag.Constructor.IS_PRIMARY to "/* primary */",
|
||||||
|
Flag.Constructor.HAS_NON_STABLE_PARAMETER_NAMES to "/* non-stable parameter names */"
|
||||||
)
|
)
|
||||||
|
|
||||||
private val FUNCTION_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
private val FUNCTION_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
||||||
@@ -973,7 +974,9 @@ private val FUNCTION_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
|||||||
Flag.Function.IS_TAILREC to "tailrec",
|
Flag.Function.IS_TAILREC to "tailrec",
|
||||||
Flag.Function.IS_EXTERNAL to "external",
|
Flag.Function.IS_EXTERNAL to "external",
|
||||||
Flag.Function.IS_SUSPEND to "suspend",
|
Flag.Function.IS_SUSPEND to "suspend",
|
||||||
Flag.Function.IS_EXPECT to "expect"
|
Flag.Function.IS_EXPECT to "expect",
|
||||||
|
|
||||||
|
Flag.Function.HAS_NON_STABLE_PARAMETER_NAMES to "/* non-stable parameter names */"
|
||||||
)
|
)
|
||||||
|
|
||||||
private val PROPERTY_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
private val PROPERTY_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
|
||||||
|
|||||||
Reference in New Issue
Block a user