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