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.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
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 = KotlinBuiltIns.getInstance().STUB;
168 DeclarationDescriptor declarationDescriptor = constructor.getDeclarationDescriptor();
169 if (declarationDescriptor instanceof ClassDescriptor) {
170 newScope = ((ClassDescriptor) declarationDescriptor).getMemberScope(newProjections);
171 }
172 return new JetTypeImpl(Collections.<AnnotationDescriptor>emptyList(), 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 }