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)
This commit is contained in:
Alexander Udalov
2013-06-27 18:33:28 +04:00
parent 1acc1564d9
commit 2841238567
3 changed files with 49 additions and 8 deletions
@@ -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());
}
}
});
@@ -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),
@@ -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);
}
}