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