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    }