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.KotlinPackage;
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.JetScope;
029 import org.jetbrains.kotlin.types.checker.JetTypeChecker;
030 import org.jetbrains.kotlin.types.typeUtil.TypeUtilPackage;
031
032 import java.util.*;
033
034 import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
035 import static org.jetbrains.kotlin.types.TypeUtils.topologicallySortSuperclassesAndRecordAllInstances;
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 JetType commonSupertypeForNonDenotableTypes(@NotNull Collection<JetType> types) {
042 if (types.isEmpty()) return null;
043 if (types.size() == 1) {
044 JetType 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 JetType commonSupertype(@NotNull Collection<JetType> 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<JetType> types) {
060 int max = 0;
061 for (JetType 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 JetType type) {
071 return 1 + maxDepth(KotlinPackage.map(type.getArguments(), new Function1<TypeProjection, JetType>() {
072 @Override
073 public JetType invoke(TypeProjection projection) {
074 if (projection.isStarProjection()) {
075 // any type is good enough for depth here
076 return KotlinBuiltIns.getInstance().getAnyType();
077 }
078 return projection.getType();
079 }
080 }));
081 }
082
083 @NotNull
084 private static JetType findCommonSupertype(@NotNull Collection<JetType> types, int recursionDepth, int maxDepth) {
085 assert recursionDepth <= maxDepth : "Recursion depth exceeded: " + recursionDepth + " > " + maxDepth + " for types " + types;
086 boolean hasFlexible = false;
087 List<JetType> upper = new ArrayList<JetType>(types.size());
088 List<JetType> lower = new ArrayList<JetType>(types.size());
089 Set<FlexibleTypeCapabilities> capabilities = new LinkedHashSet<FlexibleTypeCapabilities>();
090 for (JetType type : types) {
091 if (TypesPackage.isFlexible(type)) {
092 hasFlexible = true;
093 Flexibility flexibility = TypesPackage.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 KotlinPackage.single(capabilities) // mixing different capabilities is not supported
109 );
110 }
111
112 @NotNull
113 private static JetType commonSuperTypeForInflexible(@NotNull Collection<JetType> types, int recursionDepth, int maxDepth) {
114 assert !types.isEmpty();
115 Collection<JetType> typeSet = new HashSet<JetType>(types);
116
117 JetType bestFit = TypesPackage.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<JetType> iterator = typeSet.iterator(); iterator.hasNext();) {
124 JetType type = iterator.next();
125 assert type != null;
126 assert !TypesPackage.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 return nullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().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<JetType>> commonSupertypes = computeCommonRawSupertypes(typeSet);
148 while (commonSupertypes.size() > 1) {
149 Set<JetType> merge = new HashSet<JetType>();
150 for (Set<JetType> 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<JetType>> entry = commonSupertypes.entrySet().iterator().next();
159
160 // Reconstructing type arguments if possible
161 JetType 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<JetType>> computeCommonRawSupertypes(@NotNull Collection<JetType> types) {
169 assert !types.isEmpty();
170
171 Map<TypeConstructor, Set<JetType>> constructorToAllInstances = new HashMap<TypeConstructor, Set<JetType>>();
172 Set<TypeConstructor> commonSuperclasses = null;
173
174 List<TypeConstructor> order = null;
175 for (JetType 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<JetType>> result = new HashMap<TypeConstructor, Set<JetType>>();
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 JetType computeSupertypeProjections(@NotNull TypeConstructor constructor, @NotNull Set<JetType> 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 (JetType 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 (JetType type : types) {
228 nullable |= type.isMarkedNullable();
229 }
230
231 ClassifierDescriptor declarationDescriptor = constructor.getDeclarationDescriptor();
232 JetScope newScope;
233 if (declarationDescriptor instanceof ClassDescriptor) {
234 newScope = ((ClassDescriptor) declarationDescriptor).getMemberScope(newProjections);
235 }
236 else if (declarationDescriptor instanceof TypeParameterDescriptor) {
237 newScope = ((TypeParameterDescriptor) declarationDescriptor).getUpperBoundsAsType().getMemberScope();
238 }
239 else {
240 newScope = ErrorUtils.createErrorScope("A scope for common supertype which is not a normal classifier", true);
241 }
242 return JetTypeImpl.create(Annotations.EMPTY, constructor, nullable, newProjections, 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 = TypesPackage.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<out Any?>
259 return new TypeProjectionImpl(OUT_VARIANCE, KotlinBuiltIns.getInstance().getNullableAnyType());
260 }
261
262 Set<JetType> ins = new HashSet<JetType>();
263 Set<JetType> outs = new HashSet<JetType>();
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 Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
301 JetType superType = findCommonSupertype(outs, recursionDepth + 1, maxDepth);
302 for (JetType upperBound: parameterDescriptor.getUpperBounds()) {
303 if (!TypeUtilPackage.isSubtypeOf(superType, upperBound)) {
304 return new StarProjectionImpl(parameterDescriptor);
305 }
306 }
307 return new TypeProjectionImpl(projectionKind, superType);
308 }
309 if (ins != null) {
310 JetType intersection = TypeIntersector.intersectTypes(getBuiltIns(parameterDescriptor), JetTypeChecker.DEFAULT, ins);
311 if (intersection == null) {
312 return new TypeProjectionImpl(OUT_VARIANCE, findCommonSupertype(parameterDescriptor.getUpperBounds(), recursionDepth + 1, maxDepth));
313 }
314 Variance projectionKind = variance == IN_VARIANCE ? Variance.INVARIANT : IN_VARIANCE;
315 return new TypeProjectionImpl(projectionKind, intersection);
316 }
317 else {
318 Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
319 return new TypeProjectionImpl(projectionKind, findCommonSupertype(parameterDescriptor.getUpperBounds(), recursionDepth + 1, maxDepth));
320 }
321 }
322
323 private static void markAll(@NotNull TypeConstructor typeConstructor, @NotNull Set<TypeConstructor> markerSet) {
324 markerSet.add(typeConstructor);
325 for (JetType type : typeConstructor.getSupertypes()) {
326 markAll(type.getConstructor(), markerSet);
327 }
328 }
329 }