From 008cf03b06922a196b61ad70d6bf63bdcb102d7f Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Wed, 5 Jun 2019 14:00:43 +0300 Subject: [PATCH] [IR] Consider TypeParameter as public declaration and serialize it properly - Add test case when TypeParameter of generic property is exposed outside its module --- .../common/serialization/DeclarationTable.kt | 1 - .../DeserializeDescriptorReference.kt | 15 ++++-- .../serialization/IrModuleDeserializer.kt | 42 +++++++++-------- .../common/serialization/KotlinMangler.kt | 10 +++- .../SerializeDescriptorReference.kt | 46 +++++++++++++------ .../ir/JsDescriptorUniqIdAware.kt | 6 +-- .../properties/genericPropertyMultiModule.kt | 27 +++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 ++ .../LightAnalysisModeTestGenerated.java | 5 ++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 ++ .../IrJsCodegenBoxTestGenerated.java | 5 ++ .../semantics/JsCodegenBoxTestGenerated.java | 5 ++ 12 files changed, 129 insertions(+), 43 deletions(-) create mode 100644 compiler/testData/codegen/box/properties/genericPropertyMultiModule.kt diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeclarationTable.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeclarationTable.kt index d8926a4d61d..8ce65522301 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeclarationTable.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeclarationTable.kt @@ -42,7 +42,6 @@ abstract class DeclarationTable(val builtIns: IrBuiltIns, val descriptorTable: D val index = if (value.origin == IrDeclarationOrigin.FAKE_OVERRIDE || !value.isExported() || value is IrVariable - || (value is IrTypeParameter && value.parent !is IrClass) || value is IrValueParameter || value is IrAnonymousInitializerImpl ) { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeserializeDescriptorReference.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeserializeDescriptorReference.kt index 1721d850673..58dbc699834 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeserializeDescriptorReference.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DeserializeDescriptorReference.kt @@ -7,10 +7,8 @@ package org.jetbrains.kotlin.backend.common.serialization import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor -import org.jetbrains.kotlin.backend.common.serialization.UniqIdKey import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.backend.common.serialization.resolveFakeOverrideMaybeAbstract import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName @@ -136,7 +134,18 @@ abstract class DescriptorReferenceDeserializer( } if (isTypeParameter) { - return clazz!!.declaredTypeParameters.first { it.name.asString() == name } + + for (m in (listOfNotNull(clazz) + members)) { + val typeParameters = when (m) { + is PropertyDescriptor -> m.typeParameters + is ClassDescriptor -> m.declaredTypeParameters + is SimpleFunctionDescriptor -> m.typeParameters + is ClassConstructorDescriptor -> m.typeParameters + else -> emptyList() + } + + typeParameters.firstOrNull { it.getUniqId() == index }?.let { return it } + } } if (protoIndex?.let { checkIfSpecialDescriptorId(it) } == true) { diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt index e1b87f619cc..8539db17c3e 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/IrModuleDeserializer.kt @@ -27,11 +27,13 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.impl.* import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedTypeParameterDescriptor import org.jetbrains.kotlin.types.Variance // TODO: This code still has some uses of descriptors: @@ -823,12 +825,15 @@ abstract class IrModuleDeserializer( val symbol = deserializeIrSymbol(proto.symbol) as IrTypeParameterSymbol val name = deserializeName(proto.name) val variance = deserializeIrTypeVariance(proto.variance) + val descriptor = symbol.descriptor - val parameter = symbolTable.declareGlobalTypeParameter( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, - symbol.descriptor - ) { - IrTypeParameterImpl(start, end, origin, it, name, proto.index, proto.isReified, variance) + val parameter = if (descriptor is DeserializedTypeParameterDescriptor && descriptor.containingDeclaration is PropertyDescriptor && symbol.isBound) { + // TODO: Get rid of once new properties are implemented + IrTypeParameterImpl(start, end, origin, IrTypeParameterSymbolImpl(descriptor), name, proto.index, proto.isReified, variance) + } else { + symbolTable.declareGlobalTypeParameter(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, descriptor) { + IrTypeParameterImpl(start, end, origin, it, name, proto.index, proto.isReified, variance) + } } val superTypes = proto.superTypeList.map { deserializeIrType(it) } @@ -966,19 +971,20 @@ abstract class IrModuleDeserializer( val symbol = deserializeIrSymbol(proto.symbol) as IrSimpleFunctionSymbol val function = symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, - symbol.descriptor, { - IrFunctionImpl( - start, end, origin, it, - deserializeName(proto.base.name), - deserializeVisibility(proto.base.visibility), - deserializeModality(proto.modality), - deserializeIrType(proto.base.returnType), - proto.base.isInline, - proto.base.isExternal, - proto.isTailrec, - proto.isSuspend - ) - }) + symbol.descriptor + ) { + IrFunctionImpl( + start, end, origin, it, + deserializeName(proto.base.name), + deserializeVisibility(proto.base.visibility), + deserializeModality(proto.modality), + deserializeIrType(proto.base.returnType), + proto.base.isInline, + proto.base.isExternal, + proto.isTailrec, + proto.isSuspend + ) + } deserializeIrFunctionBase(proto.base, function as IrFunctionBase, start, end, origin) val overridden = proto.overriddenList.map { deserializeIrSymbol(it) as IrSimpleFunctionSymbol } diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinMangler.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinMangler.kt index 891380ae875..cbe3a919e84 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinMangler.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/KotlinMangler.kt @@ -200,8 +200,14 @@ abstract class KotlinManglerImpl: KotlinMangler { val IrTypeParameter.symbolName: String get() { - val containingDeclarationPart = parent.fqNameForIrSerialization - return "ktypeparam:$containingDeclarationPart$name" + + val parentDeclaration = (parent as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: parent + val containingDeclarationPart = when (parentDeclaration) { + is IrDeclarationParent -> parentDeclaration.fqNameUnique.asString() + is IrProperty -> "${parentDeclaration.parent.fqNameUnique}.${parentDeclaration.name}" + else -> error("Unexpected type parameter parent") + } + return "ktypeparam:$containingDeclarationPart$name@$index" } // This is a little extension over what's used in real mangling diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/SerializeDescriptorReference.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/SerializeDescriptorReference.kt index 8fcdb32a65c..abc4c353e9f 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/SerializeDescriptorReference.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/SerializeDescriptorReference.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.util.isAccessor import org.jetbrains.kotlin.ir.util.isGetter import org.jetbrains.kotlin.ir.util.isSetter import org.jetbrains.kotlin.ir.util.nameForIrSerialization +import org.jetbrains.kotlin.ir.util.nameForIrSerialization import org.jetbrains.kotlin.resolve.DescriptorFactory import org.jetbrains.kotlin.resolve.descriptorUtil.classId @@ -26,6 +27,21 @@ open class DescriptorReferenceSerializer( return DescriptorFactory.isEnumValueOfMethod(descriptor) || DescriptorFactory.isEnumValuesMethod(descriptor) } + fun extractPackageAndClassFqns(descriptor: DeclarationDescriptor): Pair? { + val containingDeclaration = descriptor.containingDeclaration + return when (containingDeclaration) { + is ClassDescriptor -> { + val classId = containingDeclaration.classId ?: return null + Pair(classId.packageFqName.toString(), classId.relativeClassName.toString()) + } + is PackageFragmentDescriptor -> Pair(containingDeclaration.fqName.toString(), "") + is PropertyDescriptor -> if (descriptor !is TypeParameterDescriptor) null else { + extractPackageAndClassFqns(containingDeclaration) + } + else -> return null + } + } + // Not all exported descriptors are deserialized, some a synthesized anew during metadata deserialization. // Those created descriptors can't carry the uniqIdIndex, since it is available only for deserialized descriptors. // So we record the uniq id of some other "discoverable" descriptor for which we know for sure that it will be @@ -40,21 +56,10 @@ open class DescriptorReferenceSerializer( } if (declaration is IrAnonymousInitializer) return null - if (descriptor is ParameterDescriptor || - (descriptor is VariableDescriptor && descriptor !is PropertyDescriptor) - || (declaration is IrTypeParameter && declaration.parent !is IrClass) - ) return null + if (descriptor is ParameterDescriptor || (descriptor is VariableDescriptor && descriptor !is PropertyDescriptor)) return null val containingDeclaration = descriptor.containingDeclaration!! - - val (packageFqName, classFqName) = when (containingDeclaration) { - is ClassDescriptor -> { - val classId = containingDeclaration.classId ?: return null - Pair(classId.packageFqName.toString(), classId.relativeClassName.toString()) - } - is PackageFragmentDescriptor -> Pair(containingDeclaration.fqName.toString(), "") - else -> return null - } + val (packageFqName, classFqName) = extractPackageAndClassFqns(descriptor) ?: return null val isAccessor = declaration.isAccessor val isBackingField = declaration is IrField && declaration.correspondingProperty != null @@ -62,7 +67,7 @@ open class DescriptorReferenceSerializer( val isDefaultConstructor = descriptor is ClassConstructorDescriptor && containingDeclaration is ClassDescriptor && (containingDeclaration.kind == ClassKind.OBJECT) val isEnumEntry = descriptor is ClassDescriptor && descriptor.kind == ClassKind.ENUM_ENTRY val isEnumSpecial = isEnumSpecialMember(descriptor) - val isTypeParameter = declaration is IrTypeParameter && declaration.parent is IrClass + val isTypeParameter = declaration is IrTypeParameter // The corresponding descriptor in deserialized metadata has constructors = emptyList() etc. if (containingDeclaration is ClassDescriptor && @@ -90,13 +95,24 @@ open class DescriptorReferenceSerializer( realDeclaration } + val nameString = if (isTypeParameter) { + val parent = declaration.parent + val typeParameterContainer = when (parent) { + is IrClass -> parent + is IrSimpleFunction -> parent.correspondingPropertySymbol?.owner ?: parent + is IrConstructor -> parent + else -> error("unknown type parameter container type") + } + typeParameterContainer.descriptor.name.asString() + } else descriptor.name.toString() + val uniqId = discoverableDescriptorsDeclaration?.let { declarationTable.uniqIdByDeclaration(it) } uniqId?.let { declarationTable.descriptors.put(discoverableDescriptorsDeclaration.descriptor, it) } val proto = KotlinIr.DescriptorReference.newBuilder() .setPackageFqName(serializeString(packageFqName)) .setClassFqName(serializeString(classFqName)) - .setName(serializeString(descriptor.name.toString())) + .setName(serializeString(nameString)) if (uniqId != null) proto.setUniqId(protoUniqId(uniqId)) diff --git a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsDescriptorUniqIdAware.kt b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsDescriptorUniqIdAware.kt index e37396ad718..19e073dd097 100644 --- a/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsDescriptorUniqIdAware.kt +++ b/compiler/ir/serialization.js/src/org/jetbrains/kotlin/ir/backend/js/lower/serialization/ir/JsDescriptorUniqIdAware.kt @@ -9,10 +9,7 @@ import org.jetbrains.kotlin.backend.common.serialization.DescriptorUniqIdAware import org.jetbrains.kotlin.backend.common.serialization.tryGetExtension import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataProtoBuf -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassConstructorDescriptor -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor +import org.jetbrains.kotlin.serialization.deserialization.descriptors.* object JsDescriptorUniqIdAware: DescriptorUniqIdAware { override fun DeclarationDescriptor.getUniqId(): Long? = when (this) { @@ -20,6 +17,7 @@ object JsDescriptorUniqIdAware: DescriptorUniqIdAware { is DeserializedSimpleFunctionDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.functionUniqId) is DeserializedPropertyDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.propertyUniqId) is DeserializedClassConstructorDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.constructorUniqId) + is DeserializedTypeParameterDescriptor -> this.proto.tryGetExtension(JsKlibMetadataProtoBuf.typeParamUniqId) else -> null }?.index } diff --git a/compiler/testData/codegen/box/properties/genericPropertyMultiModule.kt b/compiler/testData/codegen/box/properties/genericPropertyMultiModule.kt new file mode 100644 index 00000000000..5f0d23f8156 --- /dev/null +++ b/compiler/testData/codegen/box/properties/genericPropertyMultiModule.kt @@ -0,0 +1,27 @@ +// WITH_RUNTIME +// MODULE: lib +// FILE: common.kt + +class C(var t: T) + +var C.live: T + get() { + return t + } + set(value) { + t = value + } + +// MODULE: main(lib) +// FILE: main.kt +import kotlin.reflect.KMutableProperty0 + +fun qux(text: KMutableProperty0): String { + text.set("OK") + return text.get() +} + +fun box(): String { + val c = C("FAIL") + return qux(c::live) +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 9bb6c5b407a..72082e54b29 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -17993,6 +17993,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/properties/generalAccess.kt"); } + @TestMetadata("genericPropertyMultiModule.kt") + public void testGenericPropertyMultiModule() throws Exception { + runTest("compiler/testData/codegen/box/properties/genericPropertyMultiModule.kt"); + } + @TestMetadata("javaPropertyBoxedGetter.kt") public void testJavaPropertyBoxedGetter() throws Exception { runTest("compiler/testData/codegen/box/properties/javaPropertyBoxedGetter.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index a8f9663d78a..cf48d09410d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -17993,6 +17993,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/properties/generalAccess.kt"); } + @TestMetadata("genericPropertyMultiModule.kt") + public void testGenericPropertyMultiModule() throws Exception { + runTest("compiler/testData/codegen/box/properties/genericPropertyMultiModule.kt"); + } + @TestMetadata("javaPropertyBoxedGetter.kt") public void testJavaPropertyBoxedGetter() throws Exception { runTest("compiler/testData/codegen/box/properties/javaPropertyBoxedGetter.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 8aa1a306646..9482e59e0bd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -17998,6 +17998,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/properties/generalAccess.kt"); } + @TestMetadata("genericPropertyMultiModule.kt") + public void testGenericPropertyMultiModule() throws Exception { + runTest("compiler/testData/codegen/box/properties/genericPropertyMultiModule.kt"); + } + @TestMetadata("javaPropertyBoxedGetter.kt") public void testJavaPropertyBoxedGetter() throws Exception { runTest("compiler/testData/codegen/box/properties/javaPropertyBoxedGetter.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index bddd8fce440..3e1ea86095d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -14028,6 +14028,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/properties/generalAccess.kt"); } + @TestMetadata("genericPropertyMultiModule.kt") + public void testGenericPropertyMultiModule() throws Exception { + runTest("compiler/testData/codegen/box/properties/genericPropertyMultiModule.kt"); + } + @TestMetadata("kt10715.kt") public void testKt10715() throws Exception { runTest("compiler/testData/codegen/box/properties/kt10715.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 81ceb9797c0..f9a1a23c889 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -15183,6 +15183,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/properties/generalAccess.kt"); } + @TestMetadata("genericPropertyMultiModule.kt") + public void testGenericPropertyMultiModule() throws Exception { + runTest("compiler/testData/codegen/box/properties/genericPropertyMultiModule.kt"); + } + @TestMetadata("kt10715.kt") public void testKt10715() throws Exception { runTest("compiler/testData/codegen/box/properties/kt10715.kt");