001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.descriptors.serialization;
018    
019    import gnu.trove.TIntObjectHashMap;
020    import kotlin.Function0;
021    import kotlin.Function1;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.annotations.ReadOnly;
025    import org.jetbrains.jet.descriptors.serialization.context.DeserializationContext;
026    import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedTypeParameterDescriptor;
027    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
028    import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
029    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
030    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
031    import org.jetbrains.jet.lang.resolve.name.ClassId;
032    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
033    import org.jetbrains.jet.lang.types.*;
034    import org.jetbrains.jet.storage.MemoizedFunctionToNullable;
035    import org.jetbrains.jet.storage.NotNullLazyValue;
036    
037    import java.util.ArrayList;
038    import java.util.Collections;
039    import java.util.List;
040    
041    import static org.jetbrains.jet.descriptors.serialization.SerializationPackage.variance;
042    
043    public class TypeDeserializer {
044    
045        public interface TypeParameterResolver {
046            TypeParameterResolver NONE = new TypeParameterResolver() {
047                @NotNull
048                @Override
049                public List<DeserializedTypeParameterDescriptor> getTypeParameters(@NotNull TypeDeserializer typeDeserializer) {
050                    return Collections.emptyList();
051                }
052            };
053    
054            @NotNull
055            @ReadOnly
056            List<DeserializedTypeParameterDescriptor> getTypeParameters(@NotNull TypeDeserializer typeDeserializer);
057        }
058    
059        private final TypeDeserializer parent;
060    
061        // never written to after constructor returns
062        private final TIntObjectHashMap<TypeParameterDescriptor> typeParameterDescriptors = new TIntObjectHashMap<TypeParameterDescriptor>();
063    
064        private final MemoizedFunctionToNullable<Integer, ClassDescriptor> classDescriptors;
065    
066        private final String debugName;
067    
068        private final DeserializationContext context;
069    
070        public TypeDeserializer(
071                @NotNull DeserializationContext context,
072                @Nullable TypeDeserializer parent,
073                @NotNull String debugName,
074                @NotNull TypeParameterResolver typeParameterResolver
075        ) {
076            this.parent = parent;
077            this.debugName = debugName + (parent == null ? "" : ". Child of " + parent.debugName);
078            this.context = context;
079    
080            for (DeserializedTypeParameterDescriptor typeParameterDescriptor : typeParameterResolver.getTypeParameters(this)) {
081                typeParameterDescriptors.put(typeParameterDescriptor.getProtoId(), typeParameterDescriptor);
082            }
083    
084            this.classDescriptors = context.getStorageManager().createMemoizedFunctionWithNullableValues(
085                    new Function1<Integer, ClassDescriptor>() {
086                        @Override
087                        public ClassDescriptor invoke(Integer fqNameIndex) {
088                            return computeClassDescriptor(fqNameIndex);
089                        }
090                    });
091        }
092    
093        @Nullable
094        public JetType typeOrNull(@Nullable ProtoBuf.Type proto) {
095            if (proto == null) {
096                return null;
097            }
098            return type(proto);
099        }
100    
101        @NotNull
102        public JetType type(@NotNull ProtoBuf.Type proto) {
103            if (proto.hasFlexibleTypeCapabilitiesId()) {
104                String id = context.getNameResolver().getString(proto.getFlexibleTypeCapabilitiesId());
105                FlexibleTypeCapabilities capabilities = context.getFlexibleTypeCapabilitiesDeserializer().capabilitiesById(id);
106    
107                if (capabilities == null) return ErrorUtils.createErrorType(new DeserializedType(proto) + ": Capabilities not found for id " + id);
108    
109                return DelegatingFlexibleType.create(
110                        new DeserializedType(proto),
111                        new DeserializedType(proto.getFlexibleUpperBound()),
112                        capabilities
113                );
114            }
115            return new DeserializedType(proto);
116        }
117    
118        private TypeConstructor typeConstructor(ProtoBuf.Type proto) {
119            ProtoBuf.Type.Constructor constructorProto = proto.getConstructor();
120            int id = constructorProto.getId();
121            TypeConstructor typeConstructor = typeConstructor(constructorProto);
122            if (typeConstructor == null) {
123                String message = constructorProto.getKind() == ProtoBuf.Type.Constructor.Kind.CLASS
124                                 ? context.getNameResolver().getClassId(id).asSingleFqName().asString()
125                                 : "Unknown type parameter " + id;
126                typeConstructor = ErrorUtils.createErrorType(message).getConstructor();
127            }
128            return typeConstructor;
129        }
130    
131        @Nullable
132        private TypeConstructor typeConstructor(@NotNull ProtoBuf.Type.Constructor proto) {
133            switch (proto.getKind()) {
134                case CLASS:
135                    ClassDescriptor classDescriptor = classDescriptors.invoke(proto.getId());
136                    if (classDescriptor == null) return null;
137    
138                    return classDescriptor.getTypeConstructor();
139                case TYPE_PARAMETER:
140                    return typeParameterTypeConstructor(proto);
141            }
142            throw new IllegalStateException("Unknown kind " + proto.getKind());
143        }
144    
145        @Nullable
146        private TypeConstructor typeParameterTypeConstructor(@NotNull ProtoBuf.Type.Constructor proto) {
147            TypeParameterDescriptor descriptor = typeParameterDescriptors.get(proto.getId());
148            if (descriptor != null) {
149                return descriptor.getTypeConstructor();
150            }
151    
152            if (parent != null) {
153                return parent.typeParameterTypeConstructor(proto);
154            }
155    
156            return null;
157        }
158    
159        @Nullable
160        private ClassDescriptor computeClassDescriptor(int fqNameIndex) {
161            ClassId classId = context.getNameResolver().getClassId(fqNameIndex);
162            return SerializationPackage.findClassAcrossModuleDependencies(context.getModuleDescriptor(), classId);
163        }
164    
165        private List<TypeProjection> typeArguments(List<ProtoBuf.Type.Argument> protos) {
166            List<TypeProjection> result = new ArrayList<TypeProjection>(protos.size());
167            for (ProtoBuf.Type.Argument proto : protos) {
168                result.add(typeProjection(proto));
169            }
170            return result;
171        }
172    
173        private TypeProjection typeProjection(ProtoBuf.Type.Argument proto) {
174            return new TypeProjectionImpl(variance(proto.getProjection()), type(proto.getType()));
175        }
176    
177        @NotNull
178        private static JetScope getTypeMemberScope(@NotNull TypeConstructor constructor, @NotNull List<TypeProjection> typeArguments) {
179            ClassifierDescriptor descriptor = constructor.getDeclarationDescriptor();
180            if (descriptor instanceof TypeParameterDescriptor) {
181                TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
182                return typeParameterDescriptor.getDefaultType().getMemberScope();
183            }
184            return ((ClassDescriptor) descriptor).getMemberScope(typeArguments);
185        }
186    
187        @Override
188        public String toString() {
189            return debugName;
190        }
191    
192        private class DeserializedType extends AbstractJetType implements LazyType {
193            private final ProtoBuf.Type typeProto;
194            private final NotNullLazyValue<TypeConstructor> constructor;
195            private final List<TypeProjection> arguments;
196            private final NotNullLazyValue<JetScope> memberScope;
197    
198            public DeserializedType(@NotNull ProtoBuf.Type proto) {
199                this.typeProto = proto;
200                this.arguments = typeArguments(proto.getArgumentList());
201    
202                this.constructor = context.getStorageManager().createLazyValue(new Function0<TypeConstructor>() {
203                    @Override
204                    public TypeConstructor invoke() {
205                        return typeConstructor(typeProto);
206                    }
207                });
208                this.memberScope = context.getStorageManager().createLazyValue(new Function0<JetScope>() {
209                    @Override
210                    public JetScope invoke() {
211                        return computeMemberScope();
212                    }
213                });
214            }
215    
216            @NotNull
217            @Override
218            public TypeConstructor getConstructor() {
219                return constructor.invoke();
220            }
221    
222            @NotNull
223            @Override
224            public List<TypeProjection> getArguments() {
225                return arguments;
226            }
227    
228            @Override
229            public boolean isNullable() {
230                return typeProto.getNullable();
231            }
232    
233            @NotNull
234            private JetScope computeMemberScope() {
235                if (isError()) {
236                    return ErrorUtils.createErrorScope(getConstructor().toString());
237                }
238                else {
239                    return getTypeMemberScope(getConstructor(), getArguments());
240                }
241            }
242    
243            @NotNull
244            @Override
245            public JetScope getMemberScope() {
246                return memberScope.invoke();
247            }
248    
249            @Override
250            public boolean isError() {
251                ClassifierDescriptor descriptor = getConstructor().getDeclarationDescriptor();
252                return descriptor != null && ErrorUtils.isError(descriptor);
253            }
254    
255            @NotNull
256            @Override
257            public Annotations getAnnotations() {
258                return Annotations.EMPTY;
259            }
260        }
261    }