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