001 /*
002 * Copyright 2010-2015 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.kotlin.types;
018
019 import kotlin.CollectionsKt;
020 import kotlin.jvm.functions.Function1;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
024 import org.jetbrains.kotlin.descriptors.ClassDescriptor;
025 import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
026 import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
027 import org.jetbrains.kotlin.descriptors.annotations.Annotations;
028 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
029 import org.jetbrains.kotlin.resolve.scopes.MemberScope;
030 import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
031 import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
032 import org.jetbrains.kotlin.utils.DFS;
033
034 import java.util.*;
035
036 import static org.jetbrains.kotlin.types.Variance.IN_VARIANCE;
037 import static org.jetbrains.kotlin.types.Variance.OUT_VARIANCE;
038
039 public class CommonSupertypes {
040 @Nullable
041 public static KotlinType commonSupertypeForNonDenotableTypes(@NotNull Collection<KotlinType> types) {
042 if (types.isEmpty()) return null;
043 if (types.size() == 1) {
044 KotlinType type = types.iterator().next();
045 if (type.getConstructor() instanceof IntersectionTypeConstructor) {
046 return commonSupertypeForNonDenotableTypes(type.getConstructor().getSupertypes());
047 }
048 }
049 return commonSupertype(types);
050 }
051
052 @NotNull
053 public static KotlinType commonSupertype(@NotNull Collection<KotlinType> types) {
054 // Recursion should not be significantly deeper than the deepest type in question
055 // It can be slightly deeper, though: e.g. when initial types are simple, but their supertypes are complex
056 return findCommonSupertype(types, 0, maxDepth(types) + 3);
057 }
058
059 private static int maxDepth(@NotNull Collection<KotlinType> types) {
060 int max = 0;
061 for (KotlinType type : types) {
062 int depth = depth(type);
063 if (max < depth) {
064 max = depth;
065 }
066 }
067 return max;
068 }
069
070 private static int depth(@NotNull final KotlinType type) {
071 return 1 + maxDepth(CollectionsKt.map(type.getArguments(), new Function1<TypeProjection, KotlinType>() {
072 @Override
073 public KotlinType invoke(TypeProjection projection) {
074 if (projection.isStarProjection()) {
075 // any type is good enough for depth here
076 return type.getConstructor().getBuiltIns().getAnyType();
077 }
078 return projection.getType();
079 }
080 }));
081 }
082
083 @NotNull
084 private static KotlinType findCommonSupertype(@NotNull Collection<KotlinType> types, int recursionDepth, int maxDepth) {
085 assert recursionDepth <= maxDepth : "Recursion depth exceeded: " + recursionDepth + " > " + maxDepth + " for types " + types;
086 boolean hasFlexible = false;
087 List<KotlinType> upper = new ArrayList<KotlinType>(types.size());
088 List<KotlinType> lower = new ArrayList<KotlinType>(types.size());
089 Set<FlexibleTypeCapabilities> capabilities = new LinkedHashSet<FlexibleTypeCapabilities>();
090 for (KotlinType type : types) {
091 if (FlexibleTypesKt.isFlexible(type)) {
092 hasFlexible = true;
093 Flexibility flexibility = FlexibleTypesKt.flexibility(type);
094 upper.add(flexibility.getUpperBound());
095 lower.add(flexibility.getLowerBound());
096 capabilities.add(flexibility.getExtraCapabilities());
097 }
098 else {
099 upper.add(type);
100 lower.add(type);
101 }
102 }
103
104 if (!hasFlexible) return commonSuperTypeForInflexible(types, recursionDepth, maxDepth);
105 return DelegatingFlexibleType.create(
106 commonSuperTypeForInflexible(lower, recursionDepth, maxDepth),
107 commonSuperTypeForInflexible(upper, recursionDepth, maxDepth),
108 CollectionsKt.single(capabilities) // mixing different capabilities is not supported
109 );
110 }
111
112 @NotNull
113 private static KotlinType commonSuperTypeForInflexible(@NotNull Collection<KotlinType> types, int recursionDepth, int maxDepth) {
114 assert !types.isEmpty();
115 Collection<KotlinType> typeSet = new HashSet<KotlinType>(types);
116
117 KotlinType bestFit = FlexibleTypesKt.singleBestRepresentative(typeSet);
118 if (bestFit != null) return bestFit;
119
120 // If any of the types is nullable, the result must be nullable
121 // This also removed Nothing and Nothing? because they are subtypes of everything else
122 boolean nullable = false;
123 for (Iterator<KotlinType> iterator = typeSet.iterator(); iterator.hasNext();) {
124 KotlinType type = iterator.next();
125 assert type != null;
126 assert !FlexibleTypesKt.isFlexible(type) : "Flexible type " + type + " passed to commonSuperTypeForInflexible";
127 if (KotlinBuiltIns.isNothingOrNullableNothing(type)) {
128 iterator.remove();
129 }
130 if (type.isError()) {
131 return ErrorUtils.createErrorType("Supertype of error type " + type);
132 }
133 nullable |= type.isMarkedNullable();
134 }
135
136 // Everything deleted => it's Nothing or Nothing?
137 if (typeSet.isEmpty()) {
138 // TODO : attributes
139 KotlinBuiltIns builtIns = types.iterator().next().getConstructor().getBuiltIns();
140 return nullable ? builtIns.getNullableNothingType() : builtIns.getNothingType();
141 }
142
143 if (typeSet.size() == 1) {
144 return TypeUtils.makeNullableIfNeeded(typeSet.iterator().next(), nullable);
145 }
146
147 // constructor of the supertype -> all of its instantiations occurring as supertypes
148 Map<TypeConstructor, Set<KotlinType>> commonSupertypes = computeCommonRawSupertypes(typeSet);
149 while (commonSupertypes.size() > 1) {
150 Set<KotlinType> merge = new HashSet<KotlinType>();
151 for (Set<KotlinType> supertypes : commonSupertypes.values()) {
152 merge.addAll(supertypes);
153 }
154 commonSupertypes = computeCommonRawSupertypes(merge);
155 }
156 assert !commonSupertypes.isEmpty() : commonSupertypes + " <- " + types;
157
158 // constructor of the supertype -> all of its instantiations occurring as supertypes
159 Map.Entry<TypeConstructor, Set<KotlinType>> entry = commonSupertypes.entrySet().iterator().next();
160
161 // Reconstructing type arguments if possible
162 KotlinType result = computeSupertypeProjections(entry.getKey(), entry.getValue(), recursionDepth, maxDepth);
163 return TypeUtils.makeNullableIfNeeded(result, nullable);
164 }
165
166 // Raw supertypes are superclasses w/o type arguments
167 // @return TypeConstructor -> all instantiations of this constructor occurring as supertypes
168 @NotNull
169 private static Map<TypeConstructor, Set<KotlinType>> computeCommonRawSupertypes(@NotNull Collection<KotlinType> types) {
170 assert !types.isEmpty();
171
172 Map<TypeConstructor, Set<KotlinType>> constructorToAllInstances = new HashMap<TypeConstructor, Set<KotlinType>>();
173 Set<TypeConstructor> commonSuperclasses = null;
174
175 List<TypeConstructor> order = null;
176 for (KotlinType type : types) {
177 Set<TypeConstructor> visited = new HashSet<TypeConstructor>();
178 order = topologicallySortSuperclassesAndRecordAllInstances(type, constructorToAllInstances, visited);
179
180 if (commonSuperclasses == null) {
181 commonSuperclasses = visited;
182 }
183 else {
184 commonSuperclasses.retainAll(visited);
185 }
186 }
187 assert order != null;
188
189 Set<TypeConstructor> notSource = new HashSet<TypeConstructor>();
190 Map<TypeConstructor, Set<KotlinType>> result = new HashMap<TypeConstructor, Set<KotlinType>>();
191 for (TypeConstructor superConstructor : order) {
192 if (!commonSuperclasses.contains(superConstructor)) {
193 continue;
194 }
195
196 if (!notSource.contains(superConstructor)) {
197 result.put(superConstructor, constructorToAllInstances.get(superConstructor));
198 markAll(superConstructor, notSource);
199 }
200 }
201
202 return result;
203 }
204
205 // constructor - type constructor of a supertype to be instantiated
206 // types - instantiations of constructor occurring as supertypes of classes we are trying to intersect
207 @NotNull
208 private static KotlinType computeSupertypeProjections(@NotNull TypeConstructor constructor, @NotNull Set<KotlinType> types, int recursionDepth, int maxDepth) {
209 // we assume that all the given types are applications of the same type constructor
210
211 assert !types.isEmpty();
212
213 if (types.size() == 1) {
214 return types.iterator().next();
215 }
216
217 List<TypeParameterDescriptor> parameters = constructor.getParameters();
218 List<TypeProjection> newProjections = new ArrayList<TypeProjection>(parameters.size());
219 for (TypeParameterDescriptor parameterDescriptor : parameters) {
220 Set<TypeProjection> typeProjections = new HashSet<TypeProjection>();
221 for (KotlinType type : types) {
222 typeProjections.add(type.getArguments().get(parameterDescriptor.getIndex()));
223 }
224 newProjections.add(computeSupertypeProjection(parameterDescriptor, typeProjections, recursionDepth, maxDepth));
225 }
226
227 boolean nullable = false;
228 for (KotlinType type : types) {
229 nullable |= type.isMarkedNullable();
230 }
231
232 ClassifierDescriptor classifier = constructor.getDeclarationDescriptor();
233 MemberScope newScope;
234 if (classifier instanceof ClassDescriptor) {
235 newScope = ((ClassDescriptor) classifier).getMemberScope(newProjections);
236 }
237 else if (classifier instanceof TypeParameterDescriptor) {
238 newScope = classifier.getDefaultType().getMemberScope();
239 }
240 else {
241 newScope = ErrorUtils.createErrorScope("A scope for common supertype which is not a normal classifier", true);
242 }
243 return KotlinTypeImpl.create(Annotations.Companion.getEMPTY(), constructor, nullable, newProjections, newScope);
244 }
245
246 @NotNull
247 private static TypeProjection computeSupertypeProjection(
248 @NotNull TypeParameterDescriptor parameterDescriptor,
249 @NotNull Set<TypeProjection> typeProjections,
250 int recursionDepth, int maxDepth
251 ) {
252 TypeProjection singleBestProjection = FlexibleTypesKt.singleBestRepresentative(typeProjections);
253 if (singleBestProjection != null) {
254 return singleBestProjection;
255 }
256
257 if (recursionDepth >= maxDepth) {
258 // If recursion is too deep, we cut it by taking <out Any?> as an ultimate supertype argument
259 // Example: class A : Base<A>; class B : Base<B>, commonSuperType(A, B) = Base<out Any?>
260 return new TypeProjectionImpl(OUT_VARIANCE, DescriptorUtilsKt.getBuiltIns(parameterDescriptor).getNullableAnyType());
261 }
262
263 Set<KotlinType> ins = new HashSet<KotlinType>();
264 Set<KotlinType> outs = new HashSet<KotlinType>();
265
266 Variance variance = parameterDescriptor.getVariance();
267 switch (variance) {
268 case INVARIANT:
269 // Nothing
270 break;
271 case IN_VARIANCE:
272 outs = null;
273 break;
274 case OUT_VARIANCE:
275 ins = null;
276 break;
277 }
278
279 for (TypeProjection projection : typeProjections) {
280 Variance projectionKind = projection.getProjectionKind();
281 if (projectionKind.getAllowsInPosition()) {
282 if (ins != null) {
283 ins.add(projection.getType());
284 }
285 }
286 else {
287 ins = null;
288 }
289
290 if (projectionKind.getAllowsOutPosition()) {
291 if (outs != null) {
292 outs.add(projection.getType());
293 }
294 }
295 else {
296 outs = null;
297 }
298 }
299
300 if (outs != null) {
301 assert !outs.isEmpty() : "Out projections is empty for parameter " + parameterDescriptor + ", type projections " + typeProjections;
302 Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
303 KotlinType superType = findCommonSupertype(outs, recursionDepth + 1, maxDepth);
304 for (KotlinType upperBound: parameterDescriptor.getUpperBounds()) {
305 if (!TypeUtilsKt.isSubtypeOf(superType, upperBound)) {
306 return new StarProjectionImpl(parameterDescriptor);
307 }
308 }
309 return new TypeProjectionImpl(projectionKind, superType);
310 }
311 if (ins != null) {
312 assert !ins.isEmpty() : "In projections is empty for parameter " + parameterDescriptor + ", type projections " + typeProjections;
313 KotlinType intersection = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, ins);
314 if (intersection == null) {
315 return new TypeProjectionImpl(OUT_VARIANCE, findCommonSupertype(parameterDescriptor.getUpperBounds(), recursionDepth + 1, maxDepth));
316 }
317 Variance projectionKind = variance == IN_VARIANCE ? Variance.INVARIANT : IN_VARIANCE;
318 return new TypeProjectionImpl(projectionKind, intersection);
319 }
320 else {
321 Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
322 return new TypeProjectionImpl(projectionKind, findCommonSupertype(parameterDescriptor.getUpperBounds(), recursionDepth + 1, maxDepth));
323 }
324 }
325
326 private static void markAll(@NotNull TypeConstructor typeConstructor, @NotNull Set<TypeConstructor> markerSet) {
327 markerSet.add(typeConstructor);
328 for (KotlinType type : typeConstructor.getSupertypes()) {
329 markAll(type.getConstructor(), markerSet);
330 }
331 }
332
333 @NotNull
334 public static List<TypeConstructor> topologicallySortSuperclassesAndRecordAllInstances(
335 @NotNull KotlinType type,
336 @NotNull final Map<TypeConstructor, Set<KotlinType>> constructorToAllInstances,
337 @NotNull final Set<TypeConstructor> visited
338 ) {
339 return DFS.dfs(
340 Collections.singletonList(type),
341 new DFS.Neighbors<KotlinType>() {
342 @NotNull
343 @Override
344 public Iterable<KotlinType> getNeighbors(KotlinType current) {
345 TypeSubstitutor substitutor = TypeSubstitutor.create(current);
346 Collection<KotlinType> supertypes = current.getConstructor().getSupertypes();
347 List<KotlinType> result = new ArrayList<KotlinType>(supertypes.size());
348 for (KotlinType supertype : supertypes) {
349 if (visited.contains(supertype.getConstructor())) {
350 continue;
351 }
352 result.add(substitutor.safeSubstitute(supertype, Variance.INVARIANT));
353 }
354 return result;
355 }
356 },
357 new DFS.Visited<KotlinType>() {
358 @Override
359 public boolean checkAndMarkVisited(KotlinType current) {
360 return visited.add(current.getConstructor());
361 }
362 },
363 new DFS.NodeHandlerWithListResult<KotlinType, TypeConstructor>() {
364 @Override
365 public boolean beforeChildren(KotlinType current) {
366 TypeConstructor constructor = current.getConstructor();
367
368 Set<KotlinType> instances = constructorToAllInstances.get(constructor);
369 if (instances == null) {
370 instances = new HashSet<KotlinType>();
371 constructorToAllInstances.put(constructor, instances);
372 }
373 instances.add(current);
374
375 return true;
376 }
377
378 @Override
379 public void afterChildren(KotlinType current) {
380 result.addFirst(current.getConstructor());
381 }
382 }
383 );
384 }
385 }