diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorDeserializer.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorDeserializer.java new file mode 100644 index 00000000000..d92a95dabf5 --- /dev/null +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorDeserializer.java @@ -0,0 +1,298 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.descriptors.serialization; + +import gnu.trove.TIntObjectHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor; +import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; +import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl; +import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler; +import org.jetbrains.jet.lang.resolve.scopes.WritableScope; +import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl; +import org.jetbrains.jet.lang.types.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class DescriptorDeserializer { + @Nullable + private final DescriptorDeserializer parent; + private final DeclarationDescriptor containingDeclaration; + private final NameResolver nameResolver; + private final TIntObjectHashMap typeParameterDescriptors = new TIntObjectHashMap(); + + public DescriptorDeserializer( + @Nullable DescriptorDeserializer parent, + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull NameResolver nameResolver + ) { + this.parent = parent; + this.containingDeclaration = containingDeclaration; + this.nameResolver = nameResolver; + } + + @NotNull + private DescriptorDeserializer createChildDeserializer(@NotNull DeclarationDescriptor descriptor) { + return new DescriptorDeserializer(this, descriptor, nameResolver); + } + + private void registerTypeParameter(int id, @NotNull TypeParameterDescriptorImpl descriptor) { + typeParameterDescriptors.put(id, descriptor); + } + + @Nullable + private TypeParameterDescriptorImpl getTypeParameter(int id) { + TypeParameterDescriptorImpl descriptor = typeParameterDescriptors.get(id); + if (descriptor == null && parent != null) { + return parent.getTypeParameter(id); + } + return descriptor; + } + + @NotNull + public ClassDescriptor loadClass(@NotNull ProtoBuf.Class proto) { + MutableClassDescriptor descriptor = new MutableClassDescriptor( + containingDeclaration, + // TODO: outerScope + JetScope.EMPTY, + // TODO: kind + ClassKind.CLASS, + // TODO: isInner + false, + nameResolver.getName(proto.getName()) + ); + + + // TODO: visibility + descriptor.setVisibility(Visibilities.INTERNAL); + + // TODO: modality + descriptor.setModality(Modality.OPEN); + + DescriptorDeserializer local = createChildDeserializer(descriptor); + + descriptor.setTypeParameterDescriptors(local.typeParameters(proto.getTypeParametersList())); + + // TODO: descriptor.setPrimaryConstructor(); + + // TODO: descriptor.setAnnotations(); + + WritableScopeImpl members = new WritableScopeImpl(JetScope.EMPTY, descriptor, RedeclarationHandler.DO_NOTHING, + "Members of " + descriptor.getName()); + descriptor.setScopeForMemberLookup(members); + + for (ProtoBuf.Callable callable : proto.getMembersList()) { + // TODO: properties, classes etc + members.addFunctionDescriptor(local.loadFunction(callable)); + } + members.changeLockLevel(WritableScope.LockLevel.READING); + + List supertypes = new ArrayList(proto.getSupertypesCount()); + for (ProtoBuf.Type supertype : proto.getSupertypesList()) { + supertypes.add(local.type(supertype)); + } + descriptor.setSupertypes(supertypes); + + descriptor.createTypeConstructor(); + + return descriptor; + } + + @NotNull + public FunctionDescriptor loadFunction(@NotNull ProtoBuf.Callable proto) { + // TODO: assert function flag + + SimpleFunctionDescriptorImpl function = new SimpleFunctionDescriptorImpl( + containingDeclaration, + // TODO: annotations + Collections.emptyList(), + nameResolver.getName(proto.getName()), + // TODO: kind + CallableMemberDescriptor.Kind.DECLARATION + ); + DescriptorDeserializer local = new DescriptorDeserializer(this, function, nameResolver); + function.initialize( + local.typeOrNull(proto.hasReceiverType() ? proto.getReceiverType() : null), + // TODO: expectedThisObject + null, + local.typeParameters(proto.getTypeParametersList()), + local.valueParameters(proto.getValueParametersList()), + local.type(proto.getReturnType()), + // TODO: modality + Modality.OPEN, + // TODO: visibility + Visibilities.PUBLIC, + // TODO: inline + false + + ); + return function; + } + + @Nullable + private JetType typeOrNull(@Nullable ProtoBuf.Type proto) { + if (proto == null) { + return null; + } + return type(proto); + } + + @NotNull + private JetType type(@NotNull ProtoBuf.Type proto) { + ProtoBuf.Type.Constructor constructorProto = proto.getConstructor(); + int id = constructorProto.getId(); + TypeConstructor typeConstructor = typeConstructor(constructorProto); + if (typeConstructor == null) { + String message = constructorProto.getKind() == ProtoBuf.Type.Constructor.Kind.CLASS + ? nameResolver.getFqName(id).getFqName() + : "Unknown type parameter " + id; + return ErrorUtils.createErrorType(message); + } + + List typeArguments = typeArguments(proto.getArgumentsList()); + return new JetTypeImpl( + Collections.emptyList(), + typeConstructor, + proto.getNullable(), + typeArguments, + getTypeMemberScope(typeConstructor, typeArguments) + ); + } + + @NotNull + private static JetScope getTypeMemberScope(@NotNull TypeConstructor constructor, @NotNull List typeArguments) { + ClassifierDescriptor descriptor = constructor.getDeclarationDescriptor(); + if (descriptor instanceof TypeParameterDescriptor) { + TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor; + return typeParameterDescriptor.getDefaultType().getMemberScope(); + } + return ((ClassDescriptor) descriptor).getMemberScope(typeArguments); + } + + @Nullable + private TypeConstructor typeConstructor(@NotNull ProtoBuf.Type.Constructor proto) { + switch (proto.getKind()) { + case CLASS: + ClassDescriptor classDescriptor = nameResolver.getClassDescriptor(proto.getId()); + if (classDescriptor == null) return null; + + return classDescriptor.getTypeConstructor(); + case TYPE_PARAMETER: + TypeParameterDescriptorImpl descriptor = getTypeParameter(proto.getId()); + if (descriptor == null) return null; + + return descriptor.getTypeConstructor(); + } + throw new IllegalStateException("Unknown kind " + proto.getKind()); + } + + private List typeArguments(List protos) { + List result = new ArrayList(protos.size()); + for (ProtoBuf.Type.Argument proto : protos) { + result.add(typeProjection(proto)); + } + return result; + } + + private TypeProjection typeProjection(ProtoBuf.Type.Argument proto) { + return new TypeProjection( + variance(proto.getProjection()), + type(proto.getType()) + ); + } + + private static Variance variance(ProtoBuf.Type.Argument.Projection proto) { + switch (proto) { + case IN: + return Variance.IN_VARIANCE; + case OUT: + return Variance.OUT_VARIANCE; + case INV: + return Variance.INVARIANT; + } + throw new IllegalStateException("Unknown projection: " + proto); + } + + @NotNull + private List typeParameters(@NotNull List protos) { + List result = new ArrayList(protos.size()); + for (int i = 0; i < protos.size(); i++) { + ProtoBuf.TypeParameter proto = protos.get(i); + TypeParameterDescriptorImpl descriptor = typeParameter(proto, i); + result.add(descriptor); + } + return result; + } + + private TypeParameterDescriptorImpl typeParameter(ProtoBuf.TypeParameter proto, int index) { + int id = proto.getId(); + TypeParameterDescriptorImpl descriptor = TypeParameterDescriptorImpl.createForFurtherModification( + containingDeclaration, + // TODO + Collections.emptyList(), + proto.getReified(), + variance(proto.getVariance()), + nameResolver.getName(proto.getName()), + index); + registerTypeParameter(id, descriptor); + // TODO: circular bounds + descriptor.setInitialized(); + return descriptor; + } + + private Variance variance(ProtoBuf.TypeParameter.Variance proto) { + switch (proto) { + case IN: + return Variance.IN_VARIANCE; + case OUT: + return Variance.OUT_VARIANCE; + case INV: + return Variance.INVARIANT; + } + throw new IllegalStateException("Unknown projection: " + proto); + } + + @NotNull + private List valueParameters(@NotNull List protos) { + List result = new ArrayList(protos.size()); + for (int i = 0; i < protos.size(); i++) { + ProtoBuf.Callable.ValueParameter proto = protos.get(i); + result.add(valueParameter(proto, i)); + } + return result; + } + + private ValueParameterDescriptor valueParameter(ProtoBuf.Callable.ValueParameter proto, int index) { + return new ValueParameterDescriptorImpl( + containingDeclaration, + index, + // TODO + Collections.emptyList(), + nameResolver.getName(proto.getName()), + type(proto.getType()), + // TODO: declaresDefaultValue + false, + typeOrNull(proto.hasVarargElementType() ? proto.getVarargElementType() : null)); + } +} 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 new file mode 100644 index 00000000000..f57b0615535 --- /dev/null +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorSerializer.java @@ -0,0 +1,252 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.descriptors.serialization; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeConstructor; +import org.jetbrains.jet.lang.types.TypeProjection; +import org.jetbrains.jet.lang.types.Variance; + +public class DescriptorSerializer { + + // TODO: flags + + private final NameTable nameTable; + private final Interner typeParameters; + + public DescriptorSerializer() { + this(new NameTable(), new Interner()); + } + + private DescriptorSerializer(NameTable nameTable, Interner typeParameters) { + this.nameTable = nameTable; + this.typeParameters = typeParameters; + } + + private DescriptorSerializer createChildSerializer() { + return new DescriptorSerializer(nameTable, new Interner(typeParameters)); + } + + @NotNull + public NameTable getNameTable() { + return nameTable; + } + + @NotNull + public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) { + ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder(); + + // TODO annotations + // TODO flags + extraVisibility + builder.setName(nameTable.getSimpleNameIndex(classDescriptor.getName())); + + DescriptorSerializer local = createChildSerializer(); + + for (TypeParameterDescriptor typeParameterDescriptor : classDescriptor.getTypeConstructor().getParameters()) { + builder.addTypeParameters(local.typeParameter(typeParameterDescriptor)); + } + + for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) { + builder.addSupertypes(local.type(supertype)); + } + + // TODO: nested classes + // TODO: constructor + // TODO: class object + + for (DeclarationDescriptor descriptor : classDescriptor.getDefaultType().getMemberScope().getAllDescriptors()) { + // TODO: other than functions + if (descriptor instanceof FunctionDescriptor) { + FunctionDescriptor function = (FunctionDescriptor) descriptor; + builder.addMembers(local.functionProto(function)); + } + } + + return builder; + } + + @NotNull + public ProtoBuf.Callable.Builder functionProto(@NotNull FunctionDescriptor function) { + ProtoBuf.Callable.Builder builder = ProtoBuf.Callable.newBuilder(); + + builder.setFlags(flags(function)); + //TODO builder.setExtraVisibility() + + //TODO builder.addAnnotations() + + DescriptorSerializer local = this;//createChildSerializer(); + + for (TypeParameterDescriptor typeParameterDescriptor : function.getTypeParameters()) { + builder.addTypeParameters(local.typeParameter(typeParameterDescriptor)); + } + + ReceiverParameterDescriptor receiverParameter = function.getReceiverParameter(); + if (receiverParameter != null) { + builder.setReceiverType(local.type(receiverParameter.getType())); + } + + builder.setName(nameTable.getSimpleNameIndex(function.getName())); + + for (ValueParameterDescriptor valueParameterDescriptor : function.getValueParameters()) { + builder.addValueParameters(local.valueParameter(valueParameterDescriptor)); + } + + builder.setReturnType(local.type(function.getReturnType())); + + return builder; + } + + private int flags(FunctionDescriptor function) { + // TODO + return 0; + } + + private ProtoBuf.Callable.ValueParameter.Builder valueParameter(ValueParameterDescriptor descriptor) { + ProtoBuf.Callable.ValueParameter.Builder builder = ProtoBuf.Callable.ValueParameter.newBuilder(); + + builder.setFlags(flags(descriptor)); + + builder.setName(nameTable.getSimpleNameIndex(descriptor.getName())); + + builder.setType(type(descriptor.getType())); + + JetType varargElementType = descriptor.getVarargElementType(); + if (varargElementType != null) { + builder.setVarargElementType(type(varargElementType)); + } + + return builder; + } + + private int flags(ValueParameterDescriptor descriptor) { + // TODO + return 0; + } + + private ProtoBuf.TypeParameter.Builder typeParameter(TypeParameterDescriptor typeParameter) { + ProtoBuf.TypeParameter.Builder builder = ProtoBuf.TypeParameter.newBuilder(); + + builder.setId(getTypeParameterId(typeParameter)); + + builder.setName(nameTable.getSimpleNameIndex(typeParameter.getName())); + + // to avoid storing a default + if (typeParameter.isReified()) { + builder.setReified(true); + } + + // to avoid storing a default + ProtoBuf.TypeParameter.Variance variance = variance(typeParameter.getVariance()); + if (variance != ProtoBuf.TypeParameter.Variance.INV) { + builder.setVariance(variance); + } + + for (JetType upperBound : typeParameter.getUpperBounds()) { + builder.addUpperBounds(type(upperBound)); + } + + return builder; + } + + private static ProtoBuf.TypeParameter.Variance variance(Variance variance) { + switch (variance) { + case INVARIANT: + return ProtoBuf.TypeParameter.Variance.INV; + case IN_VARIANCE: + return ProtoBuf.TypeParameter.Variance.IN; + case OUT_VARIANCE: + return ProtoBuf.TypeParameter.Variance.OUT; + } + throw new IllegalStateException("Unknown variance: " + variance); + } + + @NotNull + public ProtoBuf.Type.Builder type(@NotNull JetType type) { + ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder(); + + builder.setConstructor(typeConstructor(type.getConstructor())); + + for (TypeProjection projection : type.getArguments()) { + builder.addArguments(typeArgument(projection)); + } + + // to avoid storing a default + if (type.isNullable()) { + builder.setNullable(true); + } + + return builder; + } + + @NotNull + private ProtoBuf.Type.Argument.Builder typeArgument(@NotNull TypeProjection typeProjection) { + ProtoBuf.Type.Argument.Builder builder = ProtoBuf.Type.Argument.newBuilder(); + ProtoBuf.Type.Argument.Projection projection = projection(typeProjection.getProjectionKind()); + + // to avoid storing a default + if (projection != ProtoBuf.Type.Argument.Projection.INV) { + builder.setProjection(projection); + } + + builder.setType(type(typeProjection.getType())); + return builder; + } + + @NotNull + private ProtoBuf.Type.Constructor.Builder typeConstructor(@NotNull TypeConstructor typeConstructor) { + ProtoBuf.Type.Constructor.Builder builder = ProtoBuf.Type.Constructor.newBuilder(); + + ClassifierDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor(); + + assert declarationDescriptor instanceof TypeParameterDescriptor || declarationDescriptor instanceof ClassDescriptor + : "Unknown declaration descriptor: " + typeConstructor; + if (declarationDescriptor instanceof TypeParameterDescriptor) { + TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor; + builder.setKind(ProtoBuf.Type.Constructor.Kind.TYPE_PARAMETER); + builder.setId(getTypeParameterId(typeParameterDescriptor)); + } + else { + ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; + //default: builder.setKind(Type.Constructor.Kind.CLASS); + builder.setId(getClassId(classDescriptor)); + } + return builder; + } + + @NotNull + private static ProtoBuf.Type.Argument.Projection projection(@NotNull Variance projectionKind) { + switch (projectionKind) { + case INVARIANT: + return ProtoBuf.Type.Argument.Projection.INV; + case IN_VARIANCE: + return ProtoBuf.Type.Argument.Projection.IN; + case OUT_VARIANCE: + return ProtoBuf.Type.Argument.Projection.OUT; + } + throw new IllegalStateException("Unknown projectionKind: " + projectionKind); + } + + private int getClassId(@NotNull ClassDescriptor descriptor) { + return nameTable.getFqNameIndex(descriptor); + } + + private int getTypeParameterId(@NotNull TypeParameterDescriptor descriptor) { + return typeParameters.intern(descriptor); + } +}