From 2841238567a1757e0aec150389d7cb3e785185c4 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 27 Jun 2013 18:33:28 +0400 Subject: [PATCH] Don't serialize non-serializable types If there's a private property in a class which has a type of some local class/object, write its type as jet.Any (otherwise there's no obvious way to construct a FQ name of such type) --- .../codegen/ImplementationBodyCodegen.java | 14 ++++---- .../serialization/DescriptorSerializer.java | 34 ++++++++++++++++++- .../jet/lang/resolve/DescriptorUtils.java | 9 +++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 3eb787227b9..6cb2635ab3a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -61,10 +61,8 @@ import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.jet.utils.ExceptionUtils; import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.util.*; import static org.jetbrains.asm4.Opcodes.*; @@ -213,21 +211,23 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor); - writeKotlinInfoIfNeeded(); + if (isTopLevelOrInnerClass(descriptor)) { + writeKotlinInfo(); + } writeClassSignatureIfNeeded(signature); } - private void writeKotlinInfoIfNeeded() { - if (!(descriptor.getContainingDeclaration() instanceof ClassOrNamespaceDescriptor)) return; - + private void writeKotlinInfo() { final AnnotationVisitor av = v.getVisitor().visitAnnotation("Ljet/KotlinInfo;", true); DescriptorSerializer serializer = new DescriptorSerializer(DescriptorNamer.DEFAULT); ClassSerializationUtil.serializeClass(descriptor, constantSerializer(serializer), new ClassSerializationUtil.Sink() { @Override public void writeClass(@NotNull ClassDescriptor classDescriptor, @NotNull ProtoBuf.Class classProto) { - av.visit("data", classProto.toByteArray()); + if (classDescriptor == descriptor) { + av.visit("data", classProto.toByteArray()); + } } }); diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorSerializer.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorSerializer.java index b10b1759897..ab090334032 100644 --- a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorSerializer.java +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorSerializer.java @@ -22,10 +22,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.Annotated; import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.renderer.DescriptorRenderer; import java.util.*; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTopLevelOrInnerClass; + public class DescriptorSerializer { private static final DescriptorRenderer RENDERER = DescriptorRenderer.STARTS_FROM_NAME; @@ -193,11 +196,40 @@ public class DescriptorSerializer { builder.addValueParameters(local.valueParameter(valueParameterDescriptor)); } - builder.setReturnType(local.type(descriptor.getReturnType())); + builder.setReturnType(local.type(getSerializableReturnType(descriptor.getReturnType()))); 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/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 20baaa52eff..9f3d8818ff1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -598,4 +598,13 @@ public class DescriptorUtils { assert descriptor != null; return descriptor; } + + /** + * @return true iff {@code descriptor}'s first non-class container is a namespace + */ + public static boolean isTopLevelOrInnerClass(@NotNull ClassDescriptor descriptor) { + DeclarationDescriptor containing = descriptor.getContainingDeclaration(); + return isTopLevelDeclaration(descriptor) || + containing instanceof ClassDescriptor && isTopLevelOrInnerClass((ClassDescriptor) containing); + } }