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 }