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    }