From 0d05fca838b2327b72b719317f4c5134f4dee771 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 13 Feb 2015 23:28:15 +0300 Subject: [PATCH] Support serialization/deserialization of local classes Most of these changes are aimed to support and correctly transform ClassId for local classes, no actual bytes are written or read at the moment (see next commits). See the comment on ClassId for clarification. A hack in DescriptorSerializer which erased anonymous types to Any (which had been breaking the consistency between descriptors resolved from sources and from serialized information) is now gone --- .../codegen/ImplementationBodyCodegen.java | 2 +- .../codegen/JvmSerializerExtension.java | 24 ++- .../kotlin/codegen/PackageCodegen.java | 2 +- .../load/kotlin/FileBasedKotlinClass.java | 15 +- .../kotlin/serialization/DebugProtoBuf.java | 174 +++++++++--------- .../kotlin/load/kotlin/JavaClassDataFinder.kt | 3 + .../org/jetbrains/kotlin/name/ClassId.java | 34 +++- core/serialization/src/descriptors.proto | 1 + .../serialization/DescriptorSerializer.java | 37 +--- .../kotlin/serialization/ProtoBuf.java | 9 + .../serialization/SerializerExtension.java | 5 + .../kotlin/serialization/StringTable.java | 19 +- .../deserialization/NameResolver.java | 57 +++--- .../deserialization/TypeDeserializer.kt | 10 +- 14 files changed, 216 insertions(+), 176 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java index 767fb8bd3c6..904f631ba19 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ImplementationBodyCodegen.java @@ -232,7 +232,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; DescriptorSerializer serializer = - DescriptorSerializer.create(descriptor, new JvmSerializerExtension(v.getSerializationBindings())); + DescriptorSerializer.create(descriptor, new JvmSerializerExtension(v.getSerializationBindings(), typeMapper)); ProtoBuf.Class classProto = serializer.classProto(descriptor).build(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmSerializerExtension.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmSerializerExtension.java index 7065e89bed9..6270ce0bb2f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmSerializerExtension.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmSerializerExtension.java @@ -19,29 +19,33 @@ package org.jetbrains.kotlin.codegen; import com.intellij.openapi.util.Pair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.serialization.deserialization.NameResolver; -import org.jetbrains.kotlin.serialization.ProtoBuf; -import org.jetbrains.kotlin.serialization.SerializerExtension; -import org.jetbrains.kotlin.serialization.StringTable; -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor; -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor; +import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.load.kotlin.SignatureDeserializer; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; +import org.jetbrains.kotlin.serialization.ProtoBuf; +import org.jetbrains.kotlin.serialization.SerializerExtension; +import org.jetbrains.kotlin.serialization.StringTable; +import org.jetbrains.kotlin.serialization.deserialization.NameResolver; +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor; +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor; import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf; import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.Arrays; +import static org.jetbrains.kotlin.codegen.AsmUtil.shortNameByAsmType; import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*; public class JvmSerializerExtension extends SerializerExtension { private final JvmSerializationBindings bindings; + private final JetTypeMapper typeMapper; - public JvmSerializerExtension(@NotNull JvmSerializationBindings bindings) { + public JvmSerializerExtension(@NotNull JvmSerializationBindings bindings, @NotNull JetTypeMapper typeMapper) { this.bindings = bindings; + this.typeMapper = typeMapper; } @Override @@ -66,6 +70,12 @@ public class JvmSerializerExtension extends SerializerExtension { } } + @Override + @NotNull + public String getLocalClassName(@NotNull ClassDescriptor descriptor) { + return shortNameByAsmType(typeMapper.mapClass(descriptor)); + } + private void saveSignature( @NotNull CallableMemberDescriptor callable, @NotNull ProtoBuf.Callable.Builder proto, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java index a426e9d0ec2..57d95ebadf3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegen.java @@ -270,7 +270,7 @@ public class PackageCodegen { if (file.isScript()) return; } - DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(new JvmSerializerExtension(bindings)); + DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(new JvmSerializerExtension(bindings, state.getTypeMapper())); Collection packageFragments = Lists.newArrayList(); ContainerUtil.addIfNotNull(packageFragments, packageFragment); ContainerUtil.addIfNotNull(packageFragments, compiledPackageFragment); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java index 515c37ed96e..a3ca6f30259 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java @@ -56,7 +56,7 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { public final String outerInternalName; public final String innerSimpleName; - private OuterAndInnerName(@NotNull String outerInternalName, @NotNull String innerSimpleName) { + private OuterAndInnerName(@Nullable String outerInternalName, @Nullable String innerSimpleName) { this.outerInternalName = outerInternalName; this.innerSimpleName = innerSimpleName; } @@ -65,7 +65,7 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { protected static class InnerClassesInfo { private Map map = null; - public void add(@NotNull String name, @NotNull String outerName, @NotNull String innerName) { + public void add(@NotNull String name, @Nullable String outerName, @Nullable String innerName) { if (map == null) { map = new HashMap(); } @@ -98,9 +98,7 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { @Override public void visitInnerClass(@NotNull String name, String outerName, String innerName, int access) { - if (outerName != null && innerName != null) { - innerClasses.add(name, outerName, innerName); - } + innerClasses.add(name, outerName, innerName); } @Override @@ -268,10 +266,15 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { } List classes = new ArrayList(1); + boolean local = false; while (true) { OuterAndInnerName outer = innerClasses.get(name); if (outer == null) break; + if (outer.outerInternalName == null) { + local = true; + break; + } classes.add(outer.innerSimpleName); name = outer.outerInternalName; } @@ -283,7 +286,7 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { FqName packageFqName = outermostClassFqName.parent(); FqNameUnsafe relativeClassName = FqNameUnsafe.fromSegments(classes); - return new ClassId(packageFqName, relativeClassName); + return new ClassId(packageFqName, relativeClassName, local); } @Override diff --git a/compiler/tests/org/jetbrains/kotlin/serialization/DebugProtoBuf.java b/compiler/tests/org/jetbrains/kotlin/serialization/DebugProtoBuf.java index 55da37a725a..88ec2e8a50e 100644 --- a/compiler/tests/org/jetbrains/kotlin/serialization/DebugProtoBuf.java +++ b/compiler/tests/org/jetbrains/kotlin/serialization/DebugProtoBuf.java @@ -1024,6 +1024,10 @@ public final class DebugProtoBuf { * PACKAGE = 1; */ PACKAGE(1, 1), + /** + * LOCAL = 2; + */ + LOCAL(2, 2), ; /** @@ -1034,6 +1038,10 @@ public final class DebugProtoBuf { * PACKAGE = 1; */ public static final int PACKAGE_VALUE = 1; + /** + * LOCAL = 2; + */ + public static final int LOCAL_VALUE = 2; public final int getNumber() { return value; } @@ -1042,6 +1050,7 @@ public final class DebugProtoBuf { switch (value) { case 0: return CLASS; case 1: return PACKAGE; + case 2: return LOCAL; default: return null; } } @@ -16536,95 +16545,96 @@ public final class DebugProtoBuf { java.lang.String[] descriptorData = { "\n.core/serialization/src/descriptors.deb" + "ug.proto\022\"org.jetbrains.kotlin.serializa" + - "tion\"\035\n\013StringTable\022\016\n\006string\030\001 \003(\t\"\275\002\n\022" + + "tion\"\035\n\013StringTable\022\016\n\006string\030\001 \003(\t\"\310\002\n\022" + "QualifiedNameTable\022\\\n\016qualified_name\030\001 \003" + "(\0132D.org.jetbrains.kotlin.serialization." + - "QualifiedNameTable.QualifiedName\032\310\001\n\rQua" + + "QualifiedNameTable.QualifiedName\032\323\001\n\rQua" + "lifiedName\022!\n\025parent_qualified_name\030\001 \001(" + "\005:\002-1\022\022\n\nshort_name\030\002 \002(\005\022`\n\004kind\030\003 \001(\0162" + "I.org.jetbrains.kotlin.serialization.Qua" + "lifiedNameTable.QualifiedName.Kind:\007PACK", - "AGE\"\036\n\004Kind\022\t\n\005CLASS\020\000\022\013\n\007PACKAGE\020\001\"\335\005\n\n" + - "Annotation\022\n\n\002id\030\001 \002(\005\022I\n\010argument\030\002 \003(\013" + - "27.org.jetbrains.kotlin.serialization.An" + - "notation.Argument\032\367\004\n\010Argument\022\017\n\007name_i" + - "d\030\001 \002(\005\022L\n\005value\030\002 \002(\0132=.org.jetbrains.k" + - "otlin.serialization.Annotation.Argument." + - "Value\032\213\004\n\005Value\022P\n\004type\030\001 \001(\0162B.org.jetb" + - "rains.kotlin.serialization.Annotation.Ar" + - "gument.Value.Type\022\021\n\tint_value\030\002 \001(\022\022\023\n\013" + - "float_value\030\003 \001(\002\022\024\n\014double_value\030\004 \001(\001\022", - "\024\n\014string_value\030\005 \001(\005\022\020\n\010class_id\030\006 \001(\005\022" + - "\025\n\renum_value_id\030\007 \001(\005\022B\n\nannotation\030\010 \001" + - "(\0132..org.jetbrains.kotlin.serialization." + - "Annotation\022T\n\rarray_element\030\t \003(\0132=.org." + + "AGE\")\n\004Kind\022\t\n\005CLASS\020\000\022\013\n\007PACKAGE\020\001\022\t\n\005L" + + "OCAL\020\002\"\335\005\n\nAnnotation\022\n\n\002id\030\001 \002(\005\022I\n\010arg" + + "ument\030\002 \003(\01327.org.jetbrains.kotlin.seria" + + "lization.Annotation.Argument\032\367\004\n\010Argumen" + + "t\022\017\n\007name_id\030\001 \002(\005\022L\n\005value\030\002 \002(\0132=.org." + "jetbrains.kotlin.serialization.Annotatio" + - "n.Argument.Value\"\230\001\n\004Type\022\010\n\004BYTE\020\000\022\010\n\004C" + - "HAR\020\001\022\t\n\005SHORT\020\002\022\007\n\003INT\020\003\022\010\n\004LONG\020\004\022\t\n\005F" + - "LOAT\020\005\022\n\n\006DOUBLE\020\006\022\013\n\007BOOLEAN\020\007\022\n\n\006STRIN" + - "G\020\010\022\t\n\005CLASS\020\t\022\010\n\004ENUM\020\n\022\016\n\nANNOTATION\020\013" + - "\022\t\n\005ARRAY\020\014\"\377\004\n\004Type\022I\n\013constructor\030\001 \002(", - "\01324.org.jetbrains.kotlin.serialization.T" + - "ype.Constructor\022C\n\010argument\030\002 \003(\01321.org." + - "jetbrains.kotlin.serialization.Type.Argu" + - "ment\022\027\n\010nullable\030\003 \001(\010:\005false\022%\n\035flexibl" + - "e_type_capabilities_id\030\004 \001(\005\022F\n\024flexible" + - "_upper_bound\030\005 \001(\0132(.org.jetbrains.kotli" + - "n.serialization.Type\032\220\001\n\013Constructor\022N\n\004" + - "kind\030\001 \001(\01629.org.jetbrains.kotlin.serial" + - "ization.Type.Constructor.Kind:\005CLASS\022\n\n\002" + - "id\030\002 \002(\005\"%\n\004Kind\022\t\n\005CLASS\020\000\022\022\n\016TYPE_PARA", - "METER\020\001\032\313\001\n\010Argument\022U\n\nprojection\030\001 \001(\016" + - "2<.org.jetbrains.kotlin.serialization.Ty" + - "pe.Argument.Projection:\003INV\0226\n\004type\030\002 \002(" + - "\0132(.org.jetbrains.kotlin.serialization.T" + - "ype\"0\n\nProjection\022\006\n\002IN\020\000\022\007\n\003OUT\020\001\022\007\n\003IN" + - "V\020\002\022\010\n\004STAR\020\003\"\371\001\n\rTypeParameter\022\n\n\002id\030\001 " + - "\002(\005\022\014\n\004name\030\002 \002(\005\022\026\n\007reified\030\003 \001(\010:\005fals" + - "e\022Q\n\010variance\030\004 \001(\0162:.org.jetbrains.kotl" + - "in.serialization.TypeParameter.Variance:" + - "\003INV\022=\n\013upper_bound\030\005 \003(\0132(.org.jetbrain", - "s.kotlin.serialization.Type\"$\n\010Variance\022" + - "\006\n\002IN\020\000\022\007\n\003OUT\020\001\022\007\n\003INV\020\002\"\340\004\n\005Class\022\020\n\005f" + - "lags\030\001 \001(\005:\0010\022\017\n\007fq_name\030\003 \002(\005\022\031\n\021class_" + - "object_name\030\004 \001(\005\022I\n\016type_parameter\030\005 \003(" + - "\01321.org.jetbrains.kotlin.serialization.T" + - "ypeParameter\022;\n\tsupertype\030\006 \003(\0132(.org.je" + - "tbrains.kotlin.serialization.Type\022\031\n\021nes" + - "ted_class_name\030\007 \003(\005\022<\n\006member\030\013 \003(\0132,.o" + - "rg.jetbrains.kotlin.serialization.Callab" + - "le\022\022\n\nenum_entry\030\014 \003(\005\022Y\n\023primary_constr", - "uctor\030\r \001(\0132<.org.jetbrains.kotlin.seria" + - "lization.Class.PrimaryConstructor\032P\n\022Pri" + - "maryConstructor\022:\n\004data\030\001 \001(\0132,.org.jetb" + - "rains.kotlin.serialization.Callable\"p\n\004K" + - "ind\022\t\n\005CLASS\020\000\022\t\n\005TRAIT\020\001\022\016\n\nENUM_CLASS\020" + - "\002\022\016\n\nENUM_ENTRY\020\003\022\024\n\020ANNOTATION_CLASS\020\004\022" + - "\n\n\006OBJECT\020\005\022\020\n\014CLASS_OBJECT\020\006*\005\010d\020\310\001\"N\n\007" + - "Package\022<\n\006member\030\001 \003(\0132,.org.jetbrains." + - "kotlin.serialization.Callable*\005\010d\020\310\001\"\300\005\n" + - "\010Callable\022\r\n\005flags\030\001 \001(\005\022\024\n\014getter_flags", - "\030\t \001(\005\022\024\n\014setter_flags\030\n \001(\005\022I\n\016type_par" + - "ameter\030\004 \003(\01321.org.jetbrains.kotlin.seri" + - "alization.TypeParameter\022?\n\rreceiver_type" + - "\030\005 \001(\0132(.org.jetbrains.kotlin.serializat" + - "ion.Type\022\014\n\004name\030\006 \002(\005\022T\n\017value_paramete" + - "r\030\007 \003(\0132;.org.jetbrains.kotlin.serializa" + - "tion.Callable.ValueParameter\022=\n\013return_t" + - "ype\030\010 \002(\0132(.org.jetbrains.kotlin.seriali" + - "zation.Type\032\263\001\n\016ValueParameter\022\r\n\005flags\030" + - "\001 \001(\005\022\014\n\004name\030\002 \002(\005\0226\n\004type\030\003 \002(\0132(.org.", - "jetbrains.kotlin.serialization.Type\022E\n\023v" + - "ararg_element_type\030\004 \001(\0132(.org.jetbrains" + - ".kotlin.serialization.Type*\005\010d\020\310\001\"Q\n\nMem" + - "berKind\022\017\n\013DECLARATION\020\000\022\021\n\rFAKE_OVERRID" + - "E\020\001\022\016\n\nDELEGATION\020\002\022\017\n\013SYNTHESIZED\020\003\":\n\014" + - "CallableKind\022\007\n\003FUN\020\000\022\007\n\003VAL\020\001\022\007\n\003VAR\020\002\022" + - "\017\n\013CONSTRUCTOR\020\003*\005\010d\020\310\001*-\n\010Modality\022\t\n\005F" + - "INAL\020\000\022\010\n\004OPEN\020\001\022\014\n\010ABSTRACT\020\002*b\n\nVisibi" + - "lity\022\014\n\010INTERNAL\020\000\022\013\n\007PRIVATE\020\001\022\r\n\tPROTE" + - "CTED\020\002\022\n\n\006PUBLIC\020\003\022\023\n\017PRIVATE_TO_THIS\020\004\022", - "\t\n\005LOCAL\020\005B\022B\rDebugProtoBuf\210\001\000" + "n.Argument.Value\032\213\004\n\005Value\022P\n\004type\030\001 \001(\016" + + "2B.org.jetbrains.kotlin.serialization.An" + + "notation.Argument.Value.Type\022\021\n\tint_valu" + + "e\030\002 \001(\022\022\023\n\013float_value\030\003 \001(\002\022\024\n\014double_v", + "alue\030\004 \001(\001\022\024\n\014string_value\030\005 \001(\005\022\020\n\010clas" + + "s_id\030\006 \001(\005\022\025\n\renum_value_id\030\007 \001(\005\022B\n\nann" + + "otation\030\010 \001(\0132..org.jetbrains.kotlin.ser" + + "ialization.Annotation\022T\n\rarray_element\030\t" + + " \003(\0132=.org.jetbrains.kotlin.serializatio" + + "n.Annotation.Argument.Value\"\230\001\n\004Type\022\010\n\004" + + "BYTE\020\000\022\010\n\004CHAR\020\001\022\t\n\005SHORT\020\002\022\007\n\003INT\020\003\022\010\n\004" + + "LONG\020\004\022\t\n\005FLOAT\020\005\022\n\n\006DOUBLE\020\006\022\013\n\007BOOLEAN" + + "\020\007\022\n\n\006STRING\020\010\022\t\n\005CLASS\020\t\022\010\n\004ENUM\020\n\022\016\n\nA" + + "NNOTATION\020\013\022\t\n\005ARRAY\020\014\"\377\004\n\004Type\022I\n\013const", + "ructor\030\001 \002(\01324.org.jetbrains.kotlin.seri" + + "alization.Type.Constructor\022C\n\010argument\030\002" + + " \003(\01321.org.jetbrains.kotlin.serializatio" + + "n.Type.Argument\022\027\n\010nullable\030\003 \001(\010:\005false" + + "\022%\n\035flexible_type_capabilities_id\030\004 \001(\005\022" + + "F\n\024flexible_upper_bound\030\005 \001(\0132(.org.jetb" + + "rains.kotlin.serialization.Type\032\220\001\n\013Cons" + + "tructor\022N\n\004kind\030\001 \001(\01629.org.jetbrains.ko" + + "tlin.serialization.Type.Constructor.Kind" + + ":\005CLASS\022\n\n\002id\030\002 \002(\005\"%\n\004Kind\022\t\n\005CLASS\020\000\022\022", + "\n\016TYPE_PARAMETER\020\001\032\313\001\n\010Argument\022U\n\nproje" + + "ction\030\001 \001(\0162<.org.jetbrains.kotlin.seria" + + "lization.Type.Argument.Projection:\003INV\0226" + + "\n\004type\030\002 \002(\0132(.org.jetbrains.kotlin.seri" + + "alization.Type\"0\n\nProjection\022\006\n\002IN\020\000\022\007\n\003" + + "OUT\020\001\022\007\n\003INV\020\002\022\010\n\004STAR\020\003\"\371\001\n\rTypeParamet" + + "er\022\n\n\002id\030\001 \002(\005\022\014\n\004name\030\002 \002(\005\022\026\n\007reified\030" + + "\003 \001(\010:\005false\022Q\n\010variance\030\004 \001(\0162:.org.jet" + + "brains.kotlin.serialization.TypeParamete" + + "r.Variance:\003INV\022=\n\013upper_bound\030\005 \003(\0132(.o", + "rg.jetbrains.kotlin.serialization.Type\"$" + + "\n\010Variance\022\006\n\002IN\020\000\022\007\n\003OUT\020\001\022\007\n\003INV\020\002\"\340\004\n" + + "\005Class\022\020\n\005flags\030\001 \001(\005:\0010\022\017\n\007fq_name\030\003 \002(" + + "\005\022\031\n\021class_object_name\030\004 \001(\005\022I\n\016type_par" + + "ameter\030\005 \003(\01321.org.jetbrains.kotlin.seri" + + "alization.TypeParameter\022;\n\tsupertype\030\006 \003" + + "(\0132(.org.jetbrains.kotlin.serialization." + + "Type\022\031\n\021nested_class_name\030\007 \003(\005\022<\n\006membe" + + "r\030\013 \003(\0132,.org.jetbrains.kotlin.serializa" + + "tion.Callable\022\022\n\nenum_entry\030\014 \003(\005\022Y\n\023pri", + "mary_constructor\030\r \001(\0132<.org.jetbrains.k" + + "otlin.serialization.Class.PrimaryConstru" + + "ctor\032P\n\022PrimaryConstructor\022:\n\004data\030\001 \001(\013" + + "2,.org.jetbrains.kotlin.serialization.Ca" + + "llable\"p\n\004Kind\022\t\n\005CLASS\020\000\022\t\n\005TRAIT\020\001\022\016\n\n" + + "ENUM_CLASS\020\002\022\016\n\nENUM_ENTRY\020\003\022\024\n\020ANNOTATI" + + "ON_CLASS\020\004\022\n\n\006OBJECT\020\005\022\020\n\014CLASS_OBJECT\020\006" + + "*\005\010d\020\310\001\"N\n\007Package\022<\n\006member\030\001 \003(\0132,.org" + + ".jetbrains.kotlin.serialization.Callable" + + "*\005\010d\020\310\001\"\300\005\n\010Callable\022\r\n\005flags\030\001 \001(\005\022\024\n\014g", + "etter_flags\030\t \001(\005\022\024\n\014setter_flags\030\n \001(\005\022" + + "I\n\016type_parameter\030\004 \003(\01321.org.jetbrains." + + "kotlin.serialization.TypeParameter\022?\n\rre" + + "ceiver_type\030\005 \001(\0132(.org.jetbrains.kotlin" + + ".serialization.Type\022\014\n\004name\030\006 \002(\005\022T\n\017val" + + "ue_parameter\030\007 \003(\0132;.org.jetbrains.kotli" + + "n.serialization.Callable.ValueParameter\022" + + "=\n\013return_type\030\010 \002(\0132(.org.jetbrains.kot" + + "lin.serialization.Type\032\263\001\n\016ValueParamete" + + "r\022\r\n\005flags\030\001 \001(\005\022\014\n\004name\030\002 \002(\005\0226\n\004type\030\003", + " \002(\0132(.org.jetbrains.kotlin.serializatio" + + "n.Type\022E\n\023vararg_element_type\030\004 \001(\0132(.or" + + "g.jetbrains.kotlin.serialization.Type*\005\010" + + "d\020\310\001\"Q\n\nMemberKind\022\017\n\013DECLARATION\020\000\022\021\n\rF" + + "AKE_OVERRIDE\020\001\022\016\n\nDELEGATION\020\002\022\017\n\013SYNTHE" + + "SIZED\020\003\":\n\014CallableKind\022\007\n\003FUN\020\000\022\007\n\003VAL\020" + + "\001\022\007\n\003VAR\020\002\022\017\n\013CONSTRUCTOR\020\003*\005\010d\020\310\001*-\n\010Mo" + + "dality\022\t\n\005FINAL\020\000\022\010\n\004OPEN\020\001\022\014\n\010ABSTRACT\020" + + "\002*b\n\nVisibility\022\014\n\010INTERNAL\020\000\022\013\n\007PRIVATE" + + "\020\001\022\r\n\tPROTECTED\020\002\022\n\n\006PUBLIC\020\003\022\023\n\017PRIVATE", + "_TO_THIS\020\004\022\t\n\005LOCAL\020\005B\022B\rDebugProtoBuf\210\001" + + "\000" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JavaClassDataFinder.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JavaClassDataFinder.kt index 8ec5245a569..01d902b2c18 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JavaClassDataFinder.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JavaClassDataFinder.kt @@ -28,6 +28,9 @@ public class JavaClassDataFinder( ) : ClassDataFinder { override fun findClassData(classId: ClassId): ClassData? { val kotlinJvmBinaryClass = kotlinClassFinder.findKotlinClass(classId) ?: return null + assert(kotlinJvmBinaryClass.getClassId() == classId) { + "Class with incorrect id found: expected $classId, actual ${kotlinJvmBinaryClass.getClassId()}" + } val data = deserializedDescriptorResolver.readData(kotlinJvmBinaryClass, KotlinClassHeader.Kind.CLASS) ?: return null return JvmProtoBufUtil.readClassDataFrom(data) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/name/ClassId.java b/core/descriptors/src/org/jetbrains/kotlin/name/ClassId.java index 1d1f7bf13b1..20929b9527d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/name/ClassId.java +++ b/core/descriptors/src/org/jetbrains/kotlin/name/ClassId.java @@ -18,6 +18,15 @@ package org.jetbrains.kotlin.name; import org.jetbrains.annotations.NotNull; +/** + * A class name which is used to uniquely identify a Kotlin class. + * + * If local = true, the class represented by this id is either itself local or is an inner class of some local class. This also means that + * the first non-class container of the class is not a package. + * In the case of a local class, relativeClassName consists of a single name including all callables' and class' names all the way up to + * the package, separated by dollar signs. If a class is an inner of local, relativeClassName would consist of two names, + * the second one being the class' short name. + */ public final class ClassId { @NotNull public static ClassId topLevel(@NotNull FqName topLevelFqName) { @@ -26,15 +35,18 @@ public final class ClassId { private final FqName packageFqName; private final FqNameUnsafe relativeClassName; + private final boolean local; - public ClassId(@NotNull FqName packageFqName, @NotNull FqNameUnsafe relativeClassName) { + public ClassId(@NotNull FqName packageFqName, @NotNull FqNameUnsafe relativeClassName, boolean local) { this.packageFqName = packageFqName; - assert !relativeClassName.isRoot() : "Class name must not be root. " + packageFqName; + assert !relativeClassName.isRoot() : + "Class name must not be root: " + packageFqName + (local ? " (local)" : ""); this.relativeClassName = relativeClassName; + this.local = local; } public ClassId(@NotNull FqName packageFqName, @NotNull Name topLevelName) { - this(packageFqName, FqNameUnsafe.topLevel(topLevelName)); + this(packageFqName, FqNameUnsafe.topLevel(topLevelName), false); } @NotNull @@ -47,14 +59,18 @@ public final class ClassId { return relativeClassName; } + public boolean isLocal() { + return local; + } + @NotNull public ClassId createNestedClassId(@NotNull Name name) { - return new ClassId(getPackageFqName(), relativeClassName.child(name)); + return new ClassId(getPackageFqName(), relativeClassName.child(name), local); } @NotNull public ClassId getOuterClassId() { - return new ClassId(getPackageFqName(), relativeClassName.parent()); + return new ClassId(getPackageFqName(), relativeClassName.parent(), local); } public boolean isNestedClass() { @@ -74,16 +90,16 @@ public final class ClassId { ClassId id = (ClassId) o; - if (!packageFqName.equals(id.packageFqName)) return false; - if (!relativeClassName.equals(id.relativeClassName)) return false; - - return true; + return packageFqName.equals(id.packageFqName) && + relativeClassName.equals(id.relativeClassName) && + local == id.local; } @Override public int hashCode() { int result = packageFqName.hashCode(); result = 31 * result + relativeClassName.hashCode(); + result = 31 * result + Boolean.valueOf(local).hashCode(); return result; } diff --git a/core/serialization/src/descriptors.proto b/core/serialization/src/descriptors.proto index 5a387deb413..ee882316716 100644 --- a/core/serialization/src/descriptors.proto +++ b/core/serialization/src/descriptors.proto @@ -35,6 +35,7 @@ message QualifiedNameTable { enum Kind { CLASS = 0; PACKAGE = 1; + LOCAL = 2; } } diff --git a/core/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java b/core/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java index 6609431f02c..5322f6b4bc5 100644 --- a/core/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java +++ b/core/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java @@ -29,7 +29,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; +import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; +import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject; public class DescriptorSerializer { @@ -45,7 +46,7 @@ public class DescriptorSerializer { @NotNull public static DescriptorSerializer createTopLevel(@NotNull SerializerExtension extension) { - return new DescriptorSerializer(new StringTable(), new Interner(), extension); + return new DescriptorSerializer(new StringTable(extension), new Interner(), extension); } @NotNull @@ -210,42 +211,14 @@ public class DescriptorSerializer { builder.addValueParameter(local.valueParameter(valueParameterDescriptor)); } - builder.setReturnType(local.type(getSerializableReturnType(descriptor.getReturnType()))); + //noinspection ConstantConditions + builder.setReturnType(local.type(descriptor.getReturnType())); extension.serializeCallable(descriptor, builder, stringTable); return builder; } - @NotNull - private static JetType getSerializableReturnType(@NotNull JetType type) { - return isSerializableType(type) ? type : KotlinBuiltIns.getInstance().getAnyType(); - } - - /** - * @return true iff this type can be serialized. Types which correspond to type parameters, top-level classes, inner classes, and - * generic classes with serializable arguments are serializable. For other types (local classes, inner of local, etc.) it may be - * problematical to construct a FQ name for serialization - */ - private static boolean isSerializableType(@NotNull JetType type) { - ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); - if (descriptor instanceof TypeParameterDescriptor) { - return true; - } - else if (descriptor instanceof ClassDescriptor) { - for (TypeProjection projection : type.getArguments()) { - if (!isSerializableType(projection.getType())) { - return false; - } - } - - return isTopLevelOrInnerClass((ClassDescriptor) descriptor); - } - else { - throw new IllegalStateException("Unknown type constructor: " + type); - } - } - private static int getAccessorFlags(@NotNull PropertyAccessorDescriptor accessor) { return Flags.getAccessorFlags( hasAnnotations(accessor), diff --git a/core/serialization/src/org/jetbrains/kotlin/serialization/ProtoBuf.java b/core/serialization/src/org/jetbrains/kotlin/serialization/ProtoBuf.java index 9f6944052b4..c7c556209f8 100644 --- a/core/serialization/src/org/jetbrains/kotlin/serialization/ProtoBuf.java +++ b/core/serialization/src/org/jetbrains/kotlin/serialization/ProtoBuf.java @@ -855,6 +855,10 @@ public final class ProtoBuf { * PACKAGE = 1; */ PACKAGE(1, 1), + /** + * LOCAL = 2; + */ + LOCAL(2, 2), ; /** @@ -865,6 +869,10 @@ public final class ProtoBuf { * PACKAGE = 1; */ public static final int PACKAGE_VALUE = 1; + /** + * LOCAL = 2; + */ + public static final int LOCAL_VALUE = 2; public final int getNumber() { return value; } @@ -873,6 +881,7 @@ public final class ProtoBuf { switch (value) { case 0: return CLASS; case 1: return PACKAGE; + case 2: return LOCAL; default: return null; } } diff --git a/core/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.java b/core/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.java index eda2def896a..b0eb4c52233 100644 --- a/core/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.java +++ b/core/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.java @@ -52,4 +52,9 @@ public abstract class SerializerExtension { @NotNull StringTable stringTable ) { } + + @NotNull + public String getLocalClassName(@NotNull ClassDescriptor descriptor) { + throw new UnsupportedOperationException("Local classes are unsupported: " + descriptor); + } } diff --git a/core/serialization/src/org/jetbrains/kotlin/serialization/StringTable.java b/core/serialization/src/org/jetbrains/kotlin/serialization/StringTable.java index 7590e2fafe7..6da0a05db48 100644 --- a/core/serialization/src/org/jetbrains/kotlin/serialization/StringTable.java +++ b/core/serialization/src/org/jetbrains/kotlin/serialization/StringTable.java @@ -60,6 +60,11 @@ public class StringTable { private final Interner strings = new Interner(); private final Interner qualifiedNames = new Interner(); + private final SerializerExtension extension; + + public StringTable(@NotNull SerializerExtension extension) { + this.extension = extension; + } @NotNull public List getStrings() { @@ -89,23 +94,33 @@ public class StringTable { if (descriptor instanceof ClassDescriptor) { builder.setKind(QualifiedName.Kind.CLASS); } - builder.setShortName(getSimpleNameIndex(descriptor.getName())); DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + int shortName; if (containingDeclaration instanceof PackageFragmentDescriptor) { + shortName = getSimpleNameIndex(descriptor.getName()); PackageFragmentDescriptor fragment = (PackageFragmentDescriptor) containingDeclaration; if (!fragment.getFqName().isRoot()) { builder.setParentQualifiedName(getFqNameIndex(fragment.getFqName())); } } else if (containingDeclaration instanceof ClassDescriptor) { + shortName = getSimpleNameIndex(descriptor.getName()); ClassDescriptor outerClass = (ClassDescriptor) containingDeclaration; builder.setParentQualifiedName(getFqNameIndex(outerClass)); } else { - throw new IllegalStateException("FQ names are only stored for top-level or inner classes: " + descriptor); + if (descriptor instanceof ClassDescriptor) { + builder.setKind(QualifiedName.Kind.LOCAL); + shortName = getStringIndex(extension.getLocalClassName((ClassDescriptor) descriptor)); + } + else { + throw new IllegalStateException("Package container should be a package: " + descriptor); + } } + builder.setShortName(shortName); + return qualifiedNames.intern(new FqNameProto(builder)); } diff --git a/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/NameResolver.java b/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/NameResolver.java index ad0fe2f5577..8a63f78f69b 100644 --- a/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/NameResolver.java +++ b/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/NameResolver.java @@ -17,13 +17,14 @@ package org.jetbrains.kotlin.serialization.deserialization; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.serialization.ProtoBuf; +import java.util.LinkedList; + import static org.jetbrains.kotlin.serialization.ProtoBuf.QualifiedNameTable.QualifiedName; public class NameResolver { @@ -61,42 +62,30 @@ public class NameResolver { @NotNull public ClassId getClassId(int index) { - QualifiedName fqNameProto = qualifiedNames.getQualifiedName(index); - assert fqNameProto.getKind() == ProtoBuf.QualifiedNameTable.QualifiedName.Kind.CLASS : "Not a class fqName: " + fqNameProto.getKind(); + LinkedList packageFqName = new LinkedList(); + LinkedList relativeClassName = new LinkedList(); + boolean local = false; - StringBuilder relativeClassName = new StringBuilder(); - QualifiedName packageFqNameProto = renderFqName(relativeClassName, fqNameProto, QualifiedName.Kind.CLASS); - - FqName packageFqName; - if (packageFqNameProto != null) { - StringBuilder sb = new StringBuilder(); - QualifiedName mustBeNull = renderFqName(sb, packageFqNameProto, QualifiedName.Kind.PACKAGE); - assert mustBeNull == null : "Prefix of an fqName must be all of kind PACKAGE"; - - packageFqName = new FqName(sb.toString()); - } - else { - packageFqName = FqName.ROOT; - } - - return new ClassId(packageFqName, new FqNameUnsafe(relativeClassName.toString())); - } - - @Nullable - private QualifiedName renderFqName(StringBuilder sb, QualifiedName fqNameProto, QualifiedName.Kind kind) { - QualifiedName result = null; - if (fqNameProto.hasParentQualifiedName()) { - QualifiedName parentProto = qualifiedNames.getQualifiedName(fqNameProto.getParentQualifiedName()); - if (kind == null || parentProto.getKind() == kind) { - result = renderFqName(sb, parentProto, kind); - sb.append("."); - } - else { - result = parentProto; + while (index != -1) { + QualifiedName proto = qualifiedNames.getQualifiedName(index); + String shortName = strings.getString(proto.getShortName()); + switch (proto.getKind()) { + case CLASS: + relativeClassName.addFirst(shortName); + break; + case PACKAGE: + packageFqName.addFirst(shortName); + break; + case LOCAL: + relativeClassName.addFirst(shortName); + local = true; + break; } + + index = proto.getParentQualifiedName(); } - sb.append(strings.getString(fqNameProto.getShortName())); - return result; + + return new ClassId(FqName.fromSegments(packageFqName), FqNameUnsafe.fromSegments(relativeClassName), local); } @NotNull diff --git a/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt b/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt index 0ffab2cd46e..c17f05ce7a5 100644 --- a/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt +++ b/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt @@ -90,8 +90,14 @@ public class TypeDeserializer( typeParameterDescriptors().get(proto.getId())?.getTypeConstructor() ?: parent?.typeParameterTypeConstructor(proto) - private fun computeClassDescriptor(fqNameIndex: Int): ClassDescriptor? = - c.components.moduleDescriptor.findClassAcrossModuleDependencies(c.nameResolver.getClassId(fqNameIndex)) + private fun computeClassDescriptor(fqNameIndex: Int): ClassDescriptor? { + val id = c.nameResolver.getClassId(fqNameIndex) + if (id.isLocal()) { + // Local classes can't be found in scopes + return c.components.deserializeClass(id) + } + return c.components.moduleDescriptor.findClassAcrossModuleDependencies(id) + } fun typeArguments(protos: List): List = protos.map { proto ->