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