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