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 return new DeserializedType(proto);
104 }
105
106 private TypeConstructor typeConstructor(ProtoBuf.Type proto) {
107 ProtoBuf.Type.Constructor constructorProto = proto.getConstructor();
108 int id = constructorProto.getId();
109 TypeConstructor typeConstructor = typeConstructor(constructorProto);
110 if (typeConstructor == null) {
111 String message = constructorProto.getKind() == ProtoBuf.Type.Constructor.Kind.CLASS
112 ? context.getNameResolver().getClassId(id).asSingleFqName().asString()
113 : "Unknown type parameter " + id;
114 typeConstructor = ErrorUtils.createErrorType(message).getConstructor();
115 }
116 return typeConstructor;
117 }
118
119 @Nullable
120 private TypeConstructor typeConstructor(@NotNull ProtoBuf.Type.Constructor proto) {
121 switch (proto.getKind()) {
122 case CLASS:
123 ClassDescriptor classDescriptor = classDescriptors.invoke(proto.getId());
124 if (classDescriptor == null) return null;
125
126 return classDescriptor.getTypeConstructor();
127 case TYPE_PARAMETER:
128 return typeParameterTypeConstructor(proto);
129 }
130 throw new IllegalStateException("Unknown kind " + proto.getKind());
131 }
132
133 @Nullable
134 private TypeConstructor typeParameterTypeConstructor(@NotNull ProtoBuf.Type.Constructor proto) {
135 TypeParameterDescriptor descriptor = typeParameterDescriptors.get(proto.getId());
136 if (descriptor != null) {
137 return descriptor.getTypeConstructor();
138 }
139
140 if (parent != null) {
141 return parent.typeParameterTypeConstructor(proto);
142 }
143
144 return null;
145 }
146
147 @Nullable
148 private ClassDescriptor computeClassDescriptor(int fqNameIndex) {
149 ClassId classId = context.getNameResolver().getClassId(fqNameIndex);
150 return SerializationPackage.findClassAcrossModuleDependencies(context.getModuleDescriptor(), classId);
151 }
152
153 private List<TypeProjection> typeArguments(List<ProtoBuf.Type.Argument> protos) {
154 List<TypeProjection> result = new ArrayList<TypeProjection>(protos.size());
155 for (ProtoBuf.Type.Argument proto : protos) {
156 result.add(typeProjection(proto));
157 }
158 return result;
159 }
160
161 private TypeProjection typeProjection(ProtoBuf.Type.Argument proto) {
162 return new TypeProjectionImpl(variance(proto.getProjection()), type(proto.getType()));
163 }
164
165 @NotNull
166 private static JetScope getTypeMemberScope(@NotNull TypeConstructor constructor, @NotNull List<TypeProjection> typeArguments) {
167 ClassifierDescriptor descriptor = constructor.getDeclarationDescriptor();
168 if (descriptor instanceof TypeParameterDescriptor) {
169 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
170 return typeParameterDescriptor.getDefaultType().getMemberScope();
171 }
172 return ((ClassDescriptor) descriptor).getMemberScope(typeArguments);
173 }
174
175 @Override
176 public String toString() {
177 return debugName;
178 }
179
180 private class DeserializedType extends AbstractJetType implements LazyType {
181 private final ProtoBuf.Type typeProto;
182 private final NotNullLazyValue<TypeConstructor> constructor;
183 private final List<TypeProjection> arguments;
184 private final NotNullLazyValue<JetScope> memberScope;
185
186 public DeserializedType(@NotNull ProtoBuf.Type proto) {
187 this.typeProto = proto;
188 this.arguments = typeArguments(proto.getArgumentList());
189
190 this.constructor = context.getStorageManager().createLazyValue(new Function0<TypeConstructor>() {
191 @Override
192 public TypeConstructor invoke() {
193 return typeConstructor(typeProto);
194 }
195 });
196 this.memberScope = context.getStorageManager().createLazyValue(new Function0<JetScope>() {
197 @Override
198 public JetScope invoke() {
199 return computeMemberScope();
200 }
201 });
202 }
203
204 @NotNull
205 @Override
206 public TypeConstructor getConstructor() {
207 return constructor.invoke();
208 }
209
210 @NotNull
211 @Override
212 public List<TypeProjection> getArguments() {
213 return arguments;
214 }
215
216 @Override
217 public boolean isNullable() {
218 return typeProto.getNullable();
219 }
220
221 @NotNull
222 private JetScope computeMemberScope() {
223 if (isError()) {
224 return ErrorUtils.createErrorScope(getConstructor().toString());
225 }
226 else {
227 return getTypeMemberScope(getConstructor(), getArguments());
228 }
229 }
230
231 @NotNull
232 @Override
233 public JetScope getMemberScope() {
234 return memberScope.invoke();
235 }
236
237 @Override
238 public boolean isError() {
239 ClassifierDescriptor descriptor = getConstructor().getDeclarationDescriptor();
240 return descriptor != null && ErrorUtils.isError(descriptor);
241 }
242
243 @NotNull
244 @Override
245 public Annotations getAnnotations() {
246 return Annotations.EMPTY;
247 }
248 }
249 }