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.lang.types;
018
019 import kotlin.Function1;
020 import kotlin.KotlinPackage;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
024 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
025 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
026 import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
027 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
028 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
029 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
030
031 import java.util.*;
032
033 import static org.jetbrains.jet.lang.types.TypeUtils.topologicallySortSuperclassesAndRecordAllInstances;
034 import static org.jetbrains.jet.lang.types.Variance.IN_VARIANCE;
035 import static org.jetbrains.jet.lang.types.Variance.OUT_VARIANCE;
036
037 public class CommonSupertypes {
038 @Nullable
039 public static JetType commonSupertypeForNonDenotableTypes(@NotNull Collection<JetType> types) {
040 if (types.isEmpty()) return null;
041 if (types.size() == 1) {
042 JetType type = types.iterator().next();
043 if (type.getConstructor() instanceof IntersectionTypeConstructor) {
044 return commonSupertypeForNonDenotableTypes(type.getConstructor().getSupertypes());
045 }
046 }
047 return commonSupertype(types);
048 }
049
050 @NotNull
051 public static JetType commonSupertype(@NotNull Collection<JetType> types) {
052 // Recursion should not be significantly deeper than the deepest type in question
053 // It can be slightly deeper, though: e.g. when initial types are simple, but their supertypes are complex
054 return findCommonSupertype(types, 0, maxDepth(types) + 3);
055 }
056
057 private static int maxDepth(@NotNull Collection<JetType> types) {
058 int max = 0;
059 for (JetType type : types) {
060 int depth = depth(type);
061 if (max < depth) {
062 max = depth;
063 }
064 }
065 return max;
066 }
067
068 private static int depth(@NotNull JetType type) {
069 return 1 + maxDepth(KotlinPackage.map(type.getArguments(), new Function1<TypeProjection, JetType>() {
070 @Override
071 public JetType invoke(TypeProjection projection) {
072 return projection.getType();
073 }
074 }));
075 }
076
077 @NotNull
078 private static JetType findCommonSupertype(@NotNull Collection<JetType> types, int recursionDepth, int maxDepth) {
079 assert recursionDepth <= maxDepth : "Recursion depth exceeded: " + recursionDepth + " > " + maxDepth + " for types " + types;
080 boolean hasFlexible = false;
081 List<JetType> upper = new ArrayList<JetType>(types.size());
082 List<JetType> lower = new ArrayList<JetType>(types.size());
083 Set<FlexibleTypeCapabilities> capabilities = new LinkedHashSet<FlexibleTypeCapabilities>();
084 for (JetType type : types) {
085 if (TypesPackage.isFlexible(type)) {
086 hasFlexible = true;
087 Flexibility flexibility = TypesPackage.flexibility(type);
088 upper.add(flexibility.getUpperBound());
089 lower.add(flexibility.getLowerBound());
090 capabilities.add(flexibility.getExtraCapabilities());
091 }
092 else {
093 upper.add(type);
094 lower.add(type);
095 }
096 }
097
098 if (!hasFlexible) return commonSuperTypeForInflexible(types, recursionDepth, maxDepth);
099 return DelegatingFlexibleType.create(
100 commonSuperTypeForInflexible(lower, recursionDepth, maxDepth),
101 commonSuperTypeForInflexible(upper, recursionDepth, maxDepth),
102 KotlinPackage.single(capabilities) // mixing different capabilities is not supported
103 );
104 }
105
106 @NotNull
107 private static JetType commonSuperTypeForInflexible(@NotNull Collection<JetType> types, int recursionDepth, int maxDepth) {
108 assert !types.isEmpty();
109 Collection<JetType> typeSet = new HashSet<JetType>(types);
110
111 JetType bestFit = TypesPackage.singleBestRepresentative(typeSet);
112 if (bestFit != null) return bestFit;
113
114 // If any of the types is nullable, the result must be nullable
115 // This also removed Nothing and Nothing? because they are subtypes of everything else
116 boolean nullable = false;
117 for (Iterator<JetType> iterator = typeSet.iterator(); iterator.hasNext();) {
118 JetType type = iterator.next();
119 assert type != null;
120 assert !TypesPackage.isFlexible(type) : "Flexible type " + type + " passed to commonSuperTypeForInflexible";
121 if (KotlinBuiltIns.getInstance().isNothingOrNullableNothing(type)) {
122 iterator.remove();
123 }
124 if (type.isError()) {
125 return ErrorUtils.createErrorType("Supertype of error type " + type);
126 }
127 nullable |= type.isNullable();
128 }
129
130 // Everything deleted => it's Nothing or Nothing?
131 if (typeSet.isEmpty()) {
132 // TODO : attributes
133 return nullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType();
134 }
135
136 if (typeSet.size() == 1) {
137 return TypeUtils.makeNullableIfNeeded(typeSet.iterator().next(), nullable);
138 }
139
140 // constructor of the supertype -> all of its instantiations occurring as supertypes
141 Map<TypeConstructor, Set<JetType>> commonSupertypes = computeCommonRawSupertypes(typeSet);
142 while (commonSupertypes.size() > 1) {
143 Set<JetType> merge = new HashSet<JetType>();
144 for (Set<JetType> supertypes : commonSupertypes.values()) {
145 merge.addAll(supertypes);
146 }
147 commonSupertypes = computeCommonRawSupertypes(merge);
148 }
149 assert !commonSupertypes.isEmpty() : commonSupertypes + " <- " + types;
150
151 // constructor of the supertype -> all of its instantiations occurring as supertypes
152 Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next();
153
154 // Reconstructing type arguments if possible
155 JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue(), recursionDepth, maxDepth);
156 return TypeUtils.makeNullableIfNeeded(result, nullable);
157 }
158
159 // Raw supertypes are superclasses w/o type arguments
160 // @return TypeConstructor -> all instantiations of this constructor occurring as supertypes
161 @NotNull
162 private static Map<TypeConstructor, Set<JetType>> computeCommonRawSupertypes(@NotNull Collection<JetType> types) {
163 assert !types.isEmpty();
164
165 Map<TypeConstructor, Set<JetType>> constructorToAllInstances = new HashMap<TypeConstructor, Set<JetType>>();
166 Set<TypeConstructor> commonSuperclasses = null;
167
168 List<TypeConstructor> order = null;
169 for (JetType type : types) {
170 Set<TypeConstructor> visited = new HashSet<TypeConstructor>();
171 order = topologicallySortSuperclassesAndRecordAllInstances(type, constructorToAllInstances, visited);
172
173 if (commonSuperclasses == null) {
174 commonSuperclasses = visited;
175 }
176 else {
177 commonSuperclasses.retainAll(visited);
178 }
179 }
180 assert order != null;
181
182 Set<TypeConstructor> notSource = new HashSet<TypeConstructor>();
183 Map<TypeConstructor, Set<JetType>> result = new HashMap<TypeConstructor, Set<JetType>>();
184 for (TypeConstructor superConstructor : order) {
185 if (!commonSuperclasses.contains(superConstructor)) {
186 continue;
187 }
188
189 if (!notSource.contains(superConstructor)) {
190 result.put(superConstructor, constructorToAllInstances.get(superConstructor));
191 markAll(superConstructor, notSource);
192 }
193 }
194
195 return result;
196 }
197
198 // constructor - type constructor of a supertype to be instantiated
199 // types - instantiations of constructor occurring as supertypes of classes we are trying to intersect
200 @NotNull
201 private static JetType computeSupertypeProjections(@NotNull TypeConstructor constructor, @NotNull Set<JetType> types, int recursionDepth, int maxDepth) {
202 // we assume that all the given types are applications of the same type constructor
203
204 assert !types.isEmpty();
205
206 if (types.size() == 1) {
207 return types.iterator().next();
208 }
209
210 List<TypeParameterDescriptor> parameters = constructor.getParameters();
211 List<TypeProjection> newProjections = new ArrayList<TypeProjection>();
212 for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
213 TypeParameterDescriptor parameterDescriptor = parameters.get(i);
214 Set<TypeProjection> typeProjections = new HashSet<TypeProjection>();
215 for (JetType type : types) {
216 typeProjections.add(type.getArguments().get(i));
217 }
218 newProjections.add(computeSupertypeProjection(parameterDescriptor, typeProjections, recursionDepth, maxDepth));
219 }
220
221 boolean nullable = false;
222 for (JetType type : types) {
223 nullable |= type.isNullable();
224 }
225
226 // TODO : attributes?
227 JetScope newScope = JetScope.EMPTY;
228 DeclarationDescriptor declarationDescriptor = constructor.getDeclarationDescriptor();
229 if (declarationDescriptor instanceof ClassDescriptor) {
230 newScope = ((ClassDescriptor) declarationDescriptor).getMemberScope(newProjections);
231 }
232 return new JetTypeImpl(Annotations.EMPTY, constructor, nullable, newProjections, newScope);
233 }
234
235 @NotNull
236 private static TypeProjection computeSupertypeProjection(
237 @NotNull TypeParameterDescriptor parameterDescriptor,
238 @NotNull Set<TypeProjection> typeProjections,
239 int recursionDepth, int maxDepth
240 ) {
241 TypeProjection singleBestProjection = TypesPackage.singleBestRepresentative(typeProjections);
242 if (singleBestProjection != null) {
243 return singleBestProjection;
244 }
245
246 if (recursionDepth >= maxDepth) {
247 // If recursion is too deep, we cut it by taking <out Any?> as an ultimate supertype argument
248 // Example: class A : Base<A>; class B : Base<B>, commonSuperType(A, B) = Base<out Any?>
249 return new TypeProjectionImpl(OUT_VARIANCE, KotlinBuiltIns.getInstance().getNullableAnyType());
250 }
251
252 Set<JetType> ins = new HashSet<JetType>();
253 Set<JetType> outs = new HashSet<JetType>();
254
255 Variance variance = parameterDescriptor.getVariance();
256 switch (variance) {
257 case INVARIANT:
258 // Nothing
259 break;
260 case IN_VARIANCE:
261 outs = null;
262 break;
263 case OUT_VARIANCE:
264 ins = null;
265 break;
266 }
267
268 for (TypeProjection projection : typeProjections) {
269 Variance projectionKind = projection.getProjectionKind();
270 if (projectionKind.allowsInPosition()) {
271 if (ins != null) {
272 ins.add(projection.getType());
273 }
274 }
275 else {
276 ins = null;
277 }
278
279 if (projectionKind.allowsOutPosition()) {
280 if (outs != null) {
281 outs.add(projection.getType());
282 }
283 }
284 else {
285 outs = null;
286 }
287 }
288
289 if (outs != null) {
290 Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
291 return new TypeProjectionImpl(projectionKind, findCommonSupertype(outs, recursionDepth + 1, maxDepth));
292 }
293 if (ins != null) {
294 JetType intersection = TypeUtils.intersect(JetTypeChecker.DEFAULT, ins);
295 if (intersection == null) {
296 return new TypeProjectionImpl(OUT_VARIANCE, findCommonSupertype(parameterDescriptor.getUpperBounds(), recursionDepth + 1, maxDepth));
297 }
298 Variance projectionKind = variance == IN_VARIANCE ? Variance.INVARIANT : IN_VARIANCE;
299 return new TypeProjectionImpl(projectionKind, intersection);
300 }
301 else {
302 Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
303 return new TypeProjectionImpl(projectionKind, findCommonSupertype(parameterDescriptor.getUpperBounds(), recursionDepth + 1, maxDepth));
304 }
305 }
306
307 private static void markAll(@NotNull TypeConstructor typeConstructor, @NotNull Set<TypeConstructor> markerSet) {
308 markerSet.add(typeConstructor);
309 for (JetType type : typeConstructor.getSupertypes()) {
310 markAll(type.getConstructor(), markerSet);
311 }
312 }
313 }