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    }