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