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 jet.Function0;
021 import jet.Function1;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedTypeParameterDescriptor;
025 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
026 import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
027 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
028 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
029 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
030 import org.jetbrains.jet.lang.types.*;
031 import org.jetbrains.jet.storage.MemoizedFunctionToNullable;
032 import org.jetbrains.jet.storage.NotNullLazyValue;
033 import org.jetbrains.jet.storage.StorageManager;
034
035 import java.util.ArrayList;
036 import java.util.Collections;
037 import java.util.List;
038
039 public class TypeDeserializer {
040
041 public interface TypeParameterResolver {
042 TypeParameterResolver NONE = new TypeParameterResolver() {
043 @NotNull
044 @Override
045 public List<DeserializedTypeParameterDescriptor> getTypeParameters(@NotNull TypeDeserializer typeDeserializer) {
046 return Collections.emptyList();
047 }
048 };
049
050 @NotNull
051 List<DeserializedTypeParameterDescriptor> getTypeParameters(@NotNull TypeDeserializer typeDeserializer);
052 }
053
054 private final NameResolver nameResolver;
055 private final DescriptorFinder descriptorFinder;
056 private final TypeDeserializer parent;
057
058 // never written to after constructor returns
059 private final TIntObjectHashMap<TypeParameterDescriptor> typeParameterDescriptors = new TIntObjectHashMap<TypeParameterDescriptor>();
060
061 private final MemoizedFunctionToNullable<Integer, ClassDescriptor> classDescriptors;
062
063 private final String debugName;
064
065 private final StorageManager storageManager;
066
067 public TypeDeserializer(
068 @NotNull StorageManager storageManager,
069 @NotNull TypeDeserializer parent,
070 @NotNull String debugName,
071 @NotNull TypeParameterResolver typeParameterResolver
072 ) {
073 this(storageManager, parent, parent.nameResolver, parent.descriptorFinder, debugName, typeParameterResolver);
074 }
075
076 public TypeDeserializer(
077 @NotNull StorageManager storageManager,
078 @Nullable TypeDeserializer parent,
079 @NotNull NameResolver nameResolver,
080 @NotNull DescriptorFinder descriptorFinder,
081 @NotNull String debugName,
082 @NotNull TypeParameterResolver typeParameterResolver
083 ) {
084 this.storageManager = storageManager;
085 this.parent = parent;
086 this.nameResolver = nameResolver;
087 this.descriptorFinder = descriptorFinder;
088 this.debugName = debugName + (parent == null ? "" : ". Child of " + parent.debugName);
089
090 for (DeserializedTypeParameterDescriptor typeParameterDescriptor : typeParameterResolver.getTypeParameters(this)) {
091 typeParameterDescriptors.put(typeParameterDescriptor.getProtoId(), typeParameterDescriptor);
092 }
093
094 this.classDescriptors = storageManager.createMemoizedFunctionWithNullableValues(new Function1<Integer, ClassDescriptor>() {
095 @Override
096 public ClassDescriptor invoke(Integer fqNameIndex) {
097 return computeClassDescriptor(fqNameIndex);
098 }
099 });
100 }
101
102 /* package */ DescriptorFinder getDescriptorFinder() {
103 return descriptorFinder;
104 }
105
106 @Nullable
107 public JetType typeOrNull(@Nullable ProtoBuf.Type proto) {
108 if (proto == null) {
109 return null;
110 }
111 return type(proto);
112 }
113
114 @NotNull
115 public JetType type(@NotNull ProtoBuf.Type proto) {
116 return new DeserializedType(proto);
117 }
118
119 private TypeConstructor typeConstructor(ProtoBuf.Type proto) {
120 ProtoBuf.Type.Constructor constructorProto = proto.getConstructor();
121 int id = constructorProto.getId();
122 TypeConstructor typeConstructor = typeConstructor(constructorProto);
123 if (typeConstructor == null) {
124 String message = constructorProto.getKind() == ProtoBuf.Type.Constructor.Kind.CLASS
125 ? nameResolver.getClassId(id).asSingleFqName().asString()
126 : "Unknown type parameter " + id;
127 typeConstructor = ErrorUtils.createErrorType(message).getConstructor();
128 }
129 return typeConstructor;
130 }
131
132 @Nullable
133 private TypeConstructor typeConstructor(@NotNull ProtoBuf.Type.Constructor proto) {
134 switch (proto.getKind()) {
135 case CLASS:
136 ClassDescriptor classDescriptor = classDescriptors.invoke(proto.getId());
137 if (classDescriptor == null) return null;
138
139 return classDescriptor.getTypeConstructor();
140 case TYPE_PARAMETER:
141 return typeParameterTypeConstructor(proto);
142 }
143 throw new IllegalStateException("Unknown kind " + proto.getKind());
144 }
145
146 @Nullable
147 private TypeConstructor typeParameterTypeConstructor(@NotNull ProtoBuf.Type.Constructor proto) {
148 TypeParameterDescriptor descriptor = typeParameterDescriptors.get(proto.getId());
149 if (descriptor != null) {
150 return descriptor.getTypeConstructor();
151 }
152
153 if (parent != null) {
154 return parent.typeParameterTypeConstructor(proto);
155 }
156
157 return null;
158 }
159
160 @Nullable
161 private ClassDescriptor computeClassDescriptor(int fqNameIndex) {
162 ClassId classId = nameResolver.getClassId(fqNameIndex);
163 return descriptorFinder.findClass(classId);
164 }
165
166 private List<TypeProjection> typeArguments(List<ProtoBuf.Type.Argument> protos) {
167 List<TypeProjection> result = new ArrayList<TypeProjection>(protos.size());
168 for (ProtoBuf.Type.Argument proto : protos) {
169 result.add(typeProjection(proto));
170 }
171 return result;
172 }
173
174 private TypeProjection typeProjection(ProtoBuf.Type.Argument proto) {
175 return new TypeProjectionImpl(
176 variance(proto.getProjection()),
177 type(proto.getType())
178 );
179 }
180
181 private static Variance variance(ProtoBuf.Type.Argument.Projection proto) {
182 switch (proto) {
183 case IN:
184 return Variance.IN_VARIANCE;
185 case OUT:
186 return Variance.OUT_VARIANCE;
187 case INV:
188 return Variance.INVARIANT;
189 }
190 throw new IllegalStateException("Unknown projection: " + proto);
191 }
192
193 @NotNull
194 private static JetScope getTypeMemberScope(@NotNull TypeConstructor constructor, @NotNull List<TypeProjection> typeArguments) {
195 ClassifierDescriptor descriptor = constructor.getDeclarationDescriptor();
196 if (descriptor instanceof TypeParameterDescriptor) {
197 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
198 return typeParameterDescriptor.getDefaultType().getMemberScope();
199 }
200 return ((ClassDescriptor) descriptor).getMemberScope(typeArguments);
201 }
202
203 @Override
204 public String toString() {
205 return debugName;
206 }
207
208 private class DeserializedType extends AbstractJetType {
209 private final ProtoBuf.Type typeProto;
210 private final NotNullLazyValue<TypeConstructor> constructor;
211 private final List<TypeProjection> arguments;
212 private final NotNullLazyValue<JetScope> memberScope;
213
214 public DeserializedType(@NotNull ProtoBuf.Type proto) {
215 this.typeProto = proto;
216 this.arguments = typeArguments(proto.getArgumentList());
217
218 this.constructor = storageManager.createLazyValue(new Function0<TypeConstructor>() {
219 @Override
220 public TypeConstructor invoke() {
221 return typeConstructor(typeProto);
222 }
223 });
224 this.memberScope = storageManager.createLazyValue(new Function0<JetScope>() {
225 @Override
226 public JetScope invoke() {
227 return computeMemberScope();
228 }
229 });
230 }
231
232 @NotNull
233 @Override
234 public TypeConstructor getConstructor() {
235 return constructor.invoke();
236 }
237
238 @NotNull
239 @Override
240 public List<TypeProjection> getArguments() {
241 return arguments;
242 }
243
244 @Override
245 public boolean isNullable() {
246 return typeProto.getNullable();
247 }
248
249 @NotNull
250 private JetScope computeMemberScope() {
251 if (isError()) {
252 return ErrorUtils.createErrorScope(getConstructor().toString());
253 }
254 else {
255 return getTypeMemberScope(getConstructor(), getArguments());
256 }
257 }
258
259 @NotNull
260 @Override
261 public JetScope getMemberScope() {
262 return memberScope.invoke();
263 }
264
265 @Override
266 public boolean isError() {
267 ClassifierDescriptor descriptor = getConstructor().getDeclarationDescriptor();
268 return descriptor != null && ErrorUtils.isError(descriptor);
269 }
270
271 @NotNull
272 @Override
273 public List<AnnotationDescriptor> getAnnotations() {
274 return Collections.emptyList();
275 }
276 }
277 }