Metadata: 'non-stable parameter names' flag for callables

^KT-34602
This commit is contained in:
Dmitriy Dolovov
2020-07-20 18:21:34 +07:00
parent 8cace2bab4
commit 3d9093583f
16 changed files with 334 additions and 15 deletions
@@ -310,7 +310,8 @@ class FirElementSerializer private constructor(
simpleFunction?.isTailRec == true,
simpleFunction?.isExternal == true,
simpleFunction?.isSuspend == true,
simpleFunction?.isExpect == true
simpleFunction?.isExpect == true,
true // TODO: supply 'hasStableParameterNames' flag for metadata
)
if (flags != builder.flags) {
builder.flags = flags
@@ -439,7 +440,8 @@ class FirElementSerializer private constructor(
val flags = Flags.getConstructorFlags(
constructor.nonSourceAnnotations(session).isNotEmpty(),
ProtoEnumFlags.visibility(normalizeVisibility(constructor)),
!constructor.isPrimary
!constructor.isPrimary,
true // TODO: supply 'hasStableParameterNames' flag for metadata
)
if (flags != builder.flags) {
builder.flags = flags
@@ -264,7 +264,9 @@ private class FirCallArgumentsProcessor(private val function: FirFunction<*>) {
private val FirExpression.argumentName: 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
get() = true
}
@@ -74,10 +74,10 @@ inline class FunctionFlags(val flags: Long) {
val modality = ProtoEnumFlags.modality(modality)
val kind = if (isFakeOverride) ProtoBuf.MemberKind.FAKE_OVERRIDE else ProtoBuf.MemberKind.DECLARATION
val flags = IrFlags.getFunctionFlags(
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()
@@ -291,6 +291,14 @@ class DescriptorSerializer private constructor(
else
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? {
if (!extension.shouldSerializeFunction(descriptor)) return null
@@ -304,7 +312,7 @@ class DescriptorSerializer private constructor(
ProtoEnumFlags.modality(descriptor.modality),
ProtoEnumFlags.memberKind(descriptor.kind),
descriptor.isOperator, descriptor.isInfix, descriptor.isInline, descriptor.isTailrec, descriptor.isExternal,
descriptor.isSuspend, descriptor.isExpect
descriptor.isSuspend, descriptor.isExpect, shouldSerializeHasStableParameterNames(descriptor)
)
if (flags != builder.flags) {
builder.flags = flags
@@ -367,7 +375,8 @@ class DescriptorSerializer private constructor(
val local = createChildSerializer(descriptor)
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) {
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
}
}
@@ -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(')')
}
}
}
@@ -15,7 +15,7 @@ class KlibMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
companion object {
@JvmField
val INSTANCE = KlibMetadataVersion(1, 4, 0)
val INSTANCE = KlibMetadataVersion(1, 4, 1)
@JvmField
val INVALID_VERSION = KlibMetadataVersion()
@@ -272,6 +272,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
ProtoEnumFlags.memberKind(Flags.MEMBER_KIND.get(flags)), proto, c.nameResolver, c.typeTable, versionRequirementTable,
c.containerSource
)
val local = c.childContext(function, proto.typeParameterList)
function.initializeWithCoroutinesExperimentalityStatus(
@@ -294,6 +295,7 @@ class MemberDeserializer(private val c: DeserializationContext) {
function.isTailrec = Flags.IS_TAILREC.get(flags)
function.isSuspend = Flags.IS_SUSPEND.get(flags)
function.isExpect = Flags.IS_EXPECT_FUNCTION.get(flags)
function.setHasStableParameterNames(!Flags.IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES.get(flags))
val mapValueForContract =
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,
c.containerSource
)
val local = c.childContext(descriptor, listOf())
descriptor.initialize(
local.memberDeserializer.valueParameters(proto.valueParameterList, proto, AnnotatedCallableKind.FUNCTION),
@@ -344,6 +347,8 @@ class MemberDeserializer(private val c: DeserializationContext) {
)
descriptor.returnType = classDescriptor.defaultType
descriptor.setHasStableParameterNames(!Flags.IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES.get(proto.flags))
val doesClassContainIncompatibility =
(c.containingDeclaration as? DeserializedClassDescriptor)
?.c?.typeDeserializer?.experimentalSuspendFunctionTypeEncountered == true
@@ -120,6 +120,7 @@ class DeserializedSimpleFunctionDescriptor(
newOwner, original as SimpleFunctionDescriptor?, annotations, newName ?: name, kind,
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source
).also {
it.setHasStableParameterNames(hasStableParameterNames())
it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode
}
}
@@ -209,7 +210,10 @@ class DeserializedClassConstructorDescriptor(
return DeserializedClassConstructorDescriptor(
newOwner as ClassDescriptor, original as ConstructorDescriptor?, annotations, isPrimary, kind,
proto, nameResolver, typeTable, versionRequirementTable, containerSource, source
).also { it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode }
).also {
it.setHasStableParameterNames(hasStableParameterNames())
it.coroutinesExperimentalCompatibilityMode = coroutinesExperimentalCompatibilityMode
}
}
override fun isExternal(): Boolean = false
@@ -26,7 +26,7 @@ class JvmMetadataVersion(versionArray: IntArray, val isStrictSemantics: Boolean)
companion object {
@JvmField
val INSTANCE = JvmMetadataVersion(1, 4, 0)
val INSTANCE = JvmMetadataVersion(1, 4, 1)
@JvmField
val INVALID_VERSION = JvmMetadataVersion()
+2
View File
@@ -270,6 +270,7 @@ message Constructor {
hasAnnotations
Visibility
isSecondary
hasNonStableParameterNames
*/
optional int32 flags = 1 [default = 6 /* public constructor, no annotations */];
@@ -294,6 +295,7 @@ message Function {
isExternal
isSuspend
isExpect
hasNonStableParameterNames
*/
optional int32 flags = 9 [default = 6 /* public final function, no annotations */];
optional int32 old_flags = 1 [default = 6];
@@ -35,6 +35,7 @@ public class Flags {
// Constructors
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
@@ -49,6 +50,7 @@ public class Flags {
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_EXPECT_FUNCTION = FlagField.booleanAfter(IS_SUSPEND);
public static final BooleanFlagField IS_FUNCTION_WITH_NON_STABLE_PARAMETER_NAMES = FlagField.booleanAfter(IS_EXPECT_FUNCTION);
// Properties
@@ -115,11 +117,13 @@ public class Flags {
public static int getConstructorFlags(
boolean hasAnnotations,
@NotNull ProtoBuf.Visibility visibility,
boolean isSecondary
boolean isSecondary,
boolean hasStableParameterNames
) {
return HAS_ANNOTATIONS.toFlags(hasAnnotations)
| VISIBILITY.toFlags(visibility)
| IS_SECONDARY.toFlags(isSecondary)
| IS_CONSTRUCTOR_WITH_NON_STABLE_PARAMETER_NAMES.toFlags(!hasStableParameterNames)
;
}
@@ -134,7 +138,8 @@ public class Flags {
boolean isTailrec,
boolean isExternal,
boolean isSuspend,
boolean isExpect
boolean isExpect,
boolean hasStableParameterNames
) {
return HAS_ANNOTATIONS.toFlags(hasAnnotations)
| VISIBILITY.toFlags(visibility)
@@ -147,6 +152,7 @@ public class Flags {
| IS_EXTERNAL_FUNCTION.toFlags(isExternal)
| IS_SUSPEND.toFlags(isSuspend)
| 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 org.jetbrains.org.objectweb.asm.ClassWriter
import org.jetbrains.org.objectweb.asm.Opcodes
import org.junit.Assert.assertEquals
import org.junit.Assert.*
import org.junit.Test
import java.net.URLClassLoader
import kotlin.coroutines.CoroutineContext
@@ -169,4 +169,38 @@ class MetadataSmokeTest {
) as KotlinClassMetadata.SyntheticClass
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
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
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(
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(
@@ -973,7 +974,9 @@ private val FUNCTION_FLAGS_MAP = COMMON_FLAGS_MAP + mapOf(
Flag.Function.IS_TAILREC to "tailrec",
Flag.Function.IS_EXTERNAL to "external",
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(