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 }