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 }