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