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 com.google.common.collect.Sets;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
023    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
024    import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
025    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
026    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
027    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
028    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
029    
030    import java.util.*;
031    
032    import static org.jetbrains.jet.lang.types.TypeUtils.topologicallySortSuperclassesAndRecordAllInstances;
033    import static org.jetbrains.jet.lang.types.Variance.IN_VARIANCE;
034    import static org.jetbrains.jet.lang.types.Variance.OUT_VARIANCE;
035    
036    public class CommonSupertypes {
037        @Nullable
038        public static JetType commonSupertypeForNonDenotableTypes(@NotNull Collection<JetType> types) {
039            if (types.isEmpty()) return null;
040            if (types.size() == 1) {
041                JetType type = types.iterator().next();
042                if (type.getConstructor() instanceof IntersectionTypeConstructor) {
043                    return commonSupertypeForNonDenotableTypes(type.getConstructor().getSupertypes());
044                }
045            }
046            return commonSupertype(types);
047        }
048    
049        @NotNull
050        public static JetType commonSupertype(@NotNull Collection<JetType> types) {
051            assert !types.isEmpty();
052            Collection<JetType> typeSet = new HashSet<JetType>(types);
053            if (typeSet.size() == 1) return typeSet.iterator().next();
054    
055            // If any of the types is nullable, the result must be nullable
056            // This also removed Nothing and Nothing? because they are subtypes of everything else
057            boolean nullable = false;
058            for (Iterator<JetType> iterator = typeSet.iterator(); iterator.hasNext();) {
059                JetType type = iterator.next();
060                assert type != null;
061                if (KotlinBuiltIns.getInstance().isNothingOrNullableNothing(type)) {
062                    iterator.remove();
063                }
064                if (type.isError()) {
065                    return ErrorUtils.createErrorType("Supertype of error type " + type);
066                }
067                nullable |= type.isNullable();
068            }
069    
070            // Everything deleted => it's Nothing or Nothing?
071            if (typeSet.isEmpty()) {
072                // TODO : attributes
073                return nullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType();
074            }
075    
076            if (typeSet.size() == 1) {
077                return TypeUtils.makeNullableIfNeeded(typeSet.iterator().next(), nullable);
078            }
079    
080            // constructor of the supertype -> all of its instantiations occurring as supertypes
081            Map<TypeConstructor, Set<JetType>> commonSupertypes = computeCommonRawSupertypes(typeSet);
082            while (commonSupertypes.size() > 1) {
083                Set<JetType> merge = new HashSet<JetType>();
084                for (Set<JetType> supertypes : commonSupertypes.values()) {
085                    merge.addAll(supertypes);
086                }
087                commonSupertypes = computeCommonRawSupertypes(merge);
088            }
089            assert !commonSupertypes.isEmpty() : commonSupertypes + " <- " + types;
090    
091            // constructor of the supertype -> all of its instantiations occurring as supertypes
092            Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next();
093    
094            // Reconstructing type arguments if possible
095            JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue());
096            return TypeUtils.makeNullableIfNeeded(result, nullable);
097        }
098    
099        // Raw supertypes are superclasses w/o type arguments
100        // @return TypeConstructor -> all instantiations of this constructor occurring as supertypes
101        @NotNull
102        private static Map<TypeConstructor, Set<JetType>> computeCommonRawSupertypes(@NotNull Collection<JetType> types) {
103            assert !types.isEmpty();
104    
105            Map<TypeConstructor, Set<JetType>> constructorToAllInstances = new HashMap<TypeConstructor, Set<JetType>>();
106            Set<TypeConstructor> commonSuperclasses = null;
107    
108            List<TypeConstructor> order = null;
109            for (JetType type : types) {
110                Set<TypeConstructor> visited = Sets.newHashSet();
111                order = topologicallySortSuperclassesAndRecordAllInstances(type, constructorToAllInstances, visited);
112    
113                if (commonSuperclasses == null) {
114                    commonSuperclasses = visited;
115                }
116                else {
117                    commonSuperclasses.retainAll(visited);
118                }
119            }
120            assert order != null;
121    
122            Set<TypeConstructor> notSource = new HashSet<TypeConstructor>();
123            Map<TypeConstructor, Set<JetType>> result = new HashMap<TypeConstructor, Set<JetType>>();
124            for (TypeConstructor superConstructor : order) {
125                if (!commonSuperclasses.contains(superConstructor)) {
126                    continue;
127                }
128    
129                if (!notSource.contains(superConstructor)) {
130                    result.put(superConstructor, constructorToAllInstances.get(superConstructor));
131                    markAll(superConstructor, notSource);
132                }
133            }
134    
135            return result;
136        }
137    
138        // constructor - type constructor of a supertype to be instantiated
139        // types - instantiations of constructor occurring as supertypes of classes we are trying to intersect
140        @NotNull
141        private static JetType computeSupertypeProjections(@NotNull TypeConstructor constructor, @NotNull Set<JetType> types) {
142            // we assume that all the given types are applications of the same type constructor
143    
144            assert !types.isEmpty();
145    
146            if (types.size() == 1) {
147                return types.iterator().next();
148            }
149    
150            List<TypeParameterDescriptor> parameters = constructor.getParameters();
151            List<TypeProjection> newProjections = new ArrayList<TypeProjection>();
152            for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
153                TypeParameterDescriptor parameterDescriptor = parameters.get(i);
154                Set<TypeProjection> typeProjections = new HashSet<TypeProjection>();
155                for (JetType type : types) {
156                    typeProjections.add(type.getArguments().get(i));
157                }
158                newProjections.add(computeSupertypeProjection(parameterDescriptor, typeProjections));
159            }
160    
161            boolean nullable = false;
162            for (JetType type : types) {
163                nullable |= type.isNullable();
164            }
165    
166            // TODO : attributes?
167            JetScope newScope = JetScope.EMPTY;
168            DeclarationDescriptor declarationDescriptor = constructor.getDeclarationDescriptor();
169            if (declarationDescriptor instanceof ClassDescriptor) {
170                newScope = ((ClassDescriptor) declarationDescriptor).getMemberScope(newProjections);
171            }
172            return new JetTypeImpl(Annotations.EMPTY, constructor, nullable, newProjections, newScope);
173        }
174    
175        @NotNull
176        private static TypeProjection computeSupertypeProjection(@NotNull TypeParameterDescriptor parameterDescriptor, @NotNull Set<TypeProjection> typeProjections) {
177            if (typeProjections.size() == 1) {
178                return typeProjections.iterator().next();
179            }
180    
181            Set<JetType> ins = new HashSet<JetType>();
182            Set<JetType> outs = new HashSet<JetType>();
183    
184            Variance variance = parameterDescriptor.getVariance();
185            switch (variance) {
186                case INVARIANT:
187                    // Nothing
188                    break;
189                case IN_VARIANCE:
190                    outs = null;
191                    break;
192                case OUT_VARIANCE:
193                    ins = null;
194                    break;
195            }
196    
197            for (TypeProjection projection : typeProjections) {
198                Variance projectionKind = projection.getProjectionKind();
199                if (projectionKind.allowsInPosition()) {
200                    if (ins != null) {
201                        ins.add(projection.getType());
202                    }
203                }
204                else {
205                    ins = null;
206                }
207    
208                if (projectionKind.allowsOutPosition()) {
209                    if (outs != null) {
210                        outs.add(projection.getType());
211                    }
212                }
213                else {
214                    outs = null;
215                }
216            }
217    
218            if (ins != null) {
219                JetType intersection = TypeUtils.intersect(JetTypeChecker.INSTANCE, ins);
220                if (intersection == null) {
221                    if (outs != null) {
222                        return new TypeProjectionImpl(OUT_VARIANCE, commonSupertype(outs));
223                    }
224                    return new TypeProjectionImpl(OUT_VARIANCE, commonSupertype(parameterDescriptor.getUpperBounds()));
225                }
226                Variance projectionKind = variance == IN_VARIANCE ? Variance.INVARIANT : IN_VARIANCE;
227                return new TypeProjectionImpl(projectionKind, intersection);
228            }
229            else if (outs != null) {
230                Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
231                return new TypeProjectionImpl(projectionKind, commonSupertype(outs));
232            }
233            else {
234                Variance projectionKind = variance == OUT_VARIANCE ? Variance.INVARIANT : OUT_VARIANCE;
235                return new TypeProjectionImpl(projectionKind, commonSupertype(parameterDescriptor.getUpperBounds()));
236            }
237        }
238    
239        private static void markAll(@NotNull TypeConstructor typeConstructor, @NotNull Set<TypeConstructor> markerSet) {
240            markerSet.add(typeConstructor);
241            for (JetType type : typeConstructor.getSupertypes()) {
242                markAll(type.getConstructor(), markerSet);
243            }
244        }
245    }