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.resolve;
018
019 import com.google.common.collect.BiMap;
020 import com.google.common.collect.HashBiMap;
021 import com.google.common.collect.Maps;
022 import com.google.common.collect.Sets;
023 import com.intellij.util.Function;
024 import com.intellij.util.containers.ContainerUtil;
025 import org.jetbrains.annotations.NotNull;
026 import org.jetbrains.annotations.Nullable;
027 import org.jetbrains.jet.lang.descriptors.*;
028 import org.jetbrains.jet.lang.types.*;
029 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
030
031 import java.util.*;
032
033 public class OverridingUtil {
034
035 private static final List<ExternalOverridabilityCondition> EXTERNAL_CONDITIONS =
036 ContainerUtil.collect(ServiceLoader.load(
037 ExternalOverridabilityCondition.class,
038 ExternalOverridabilityCondition.class.getClassLoader()).iterator()
039 );
040
041 private OverridingUtil() {
042 }
043
044 public static <D extends CallableDescriptor> Set<D> filterOverrides(Set<D> candidateSet) {
045 return filterOverrides(candidateSet, Function.ID);
046 }
047
048 public static <D> Set<D> filterOverrides(Set<D> candidateSet, Function<? super D, ? extends CallableDescriptor> transform) {
049 Set<D> candidates = Sets.newLinkedHashSet();
050 outerLoop:
051 for (D meD : candidateSet) {
052 CallableDescriptor me = transform.fun(meD);
053 for (D otherD : candidateSet) {
054 CallableDescriptor other = transform.fun(otherD);
055 if (me == other) continue;
056 if (overrides(other, me)) {
057 continue outerLoop;
058 }
059 }
060 for (D otherD : candidates) {
061 CallableDescriptor other = transform.fun(otherD);
062 if (me.getOriginal() == other.getOriginal()
063 && isOverridableBy(other, me).getResult() == OverrideCompatibilityInfo.Result.OVERRIDABLE
064 && isOverridableBy(me, other).getResult() == OverrideCompatibilityInfo.Result.OVERRIDABLE) {
065 continue outerLoop;
066 }
067 }
068 // System.out.println(me);
069 candidates.add(meD);
070 }
071 // Set<D> candidates = Sets.newLinkedHashSet(candidateSet);
072 // for (D descriptor : candidateSet) {
073 // Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
074 // getAllOverriddenDescriptors(descriptor.getOriginal(), overriddenDescriptors);
075 // candidates.removeAll(overriddenDescriptors);
076 // }
077 return candidates;
078 }
079
080 public static <Descriptor extends CallableDescriptor> boolean overrides(@NotNull Descriptor f, @NotNull Descriptor g) {
081 Set<CallableDescriptor> overriddenDescriptors = Sets.newHashSet();
082 getAllOverriddenDescriptors(f.getOriginal(), overriddenDescriptors);
083 CallableDescriptor originalG = g.getOriginal();
084 for (CallableDescriptor overriddenFunction : overriddenDescriptors) {
085 if (originalG.equals(overriddenFunction.getOriginal())) return true;
086 }
087 return false;
088 }
089
090 private static void getAllOverriddenDescriptors(@NotNull CallableDescriptor current, @NotNull Set<CallableDescriptor> overriddenDescriptors) {
091 if (overriddenDescriptors.contains(current)) return;
092 for (CallableDescriptor descriptor : current.getOriginal().getOverriddenDescriptors()) {
093 getAllOverriddenDescriptors(descriptor, overriddenDescriptors);
094 overriddenDescriptors.add(descriptor);
095 }
096 }
097
098 @NotNull
099 public static OverrideCompatibilityInfo isOverridableBy(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
100 if (superDescriptor instanceof FunctionDescriptor) {
101 if (!(subDescriptor instanceof FunctionDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
102 }
103 else if (superDescriptor instanceof PropertyDescriptor) {
104 if (!(subDescriptor instanceof PropertyDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
105 }
106 else {
107 throw new IllegalArgumentException("This type of CallableDescriptor cannot be checked for overridability: " + superDescriptor);
108 }
109
110 // TODO: check outside of this method
111 if (!superDescriptor.getName().equals(subDescriptor.getName())) {
112 return OverrideCompatibilityInfo.nameMismatch();
113 }
114
115 return isOverridableByImpl(superDescriptor, subDescriptor, true);
116 }
117
118 private static List<JetType> compiledValueParameters(CallableDescriptor callableDescriptor) {
119 ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
120 ArrayList<JetType> parameters = new ArrayList<JetType>();
121 if (receiverParameter != null) {
122 parameters.add(receiverParameter.getType());
123 }
124 for (ValueParameterDescriptor valueParameterDescriptor : callableDescriptor.getValueParameters()) {
125 parameters.add(valueParameterDescriptor.getType());
126 }
127 return parameters;
128 }
129
130 /**
131 * @param forOverride true for override, false for overload
132 */
133 static OverrideCompatibilityInfo isOverridableByImpl(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean forOverride) {
134
135 // TODO : Visibility
136
137 if ((superDescriptor.getReceiverParameter() == null) != (subDescriptor.getReceiverParameter() == null)) {
138 return OverrideCompatibilityInfo.receiverPresenceMismatch();
139 }
140
141 if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
142 return OverrideCompatibilityInfo.valueParameterNumberMismatch();
143 }
144
145 List<JetType> superValueParameters = compiledValueParameters(superDescriptor);
146 List<JetType> subValueParameters = compiledValueParameters(subDescriptor);
147
148 if (forOverride) {
149 if (superDescriptor.getTypeParameters().size() != subDescriptor.getTypeParameters().size()) {
150 for (int i = 0; i < superValueParameters.size(); ++i) {
151 JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
152 JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
153 // TODO: compare erasure
154 if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
155 return OverrideCompatibilityInfo.typeParameterNumberMismatch();
156 }
157 }
158 return OverrideCompatibilityInfo.valueParameterTypeMismatch(null, null, OverrideCompatibilityInfo.Result.CONFLICT);
159 }
160 }
161
162 if (forOverride) {
163
164 List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
165 List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
166
167 BiMap<TypeConstructor, TypeConstructor> axioms = HashBiMap.create();
168 for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
169 TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
170 TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
171 axioms.put(superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor());
172 }
173
174 for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
175 TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
176 TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
177
178 if (!JetTypeChecker.INSTANCE.equalTypes(superTypeParameter.getUpperBoundsAsType(), subTypeParameter.getUpperBoundsAsType(), axioms)) {
179 return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
180 }
181 }
182
183 for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
184 JetType superValueParameter = superValueParameters.get(i);
185 JetType subValueParameter = subValueParameters.get(i);
186
187 boolean bothErrors = ErrorUtils.isErrorType(superValueParameter) && ErrorUtils.isErrorType(subValueParameter);
188 if (!bothErrors && !JetTypeChecker.INSTANCE.equalTypes(superValueParameter, subValueParameter, axioms)) {
189 return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameter, subValueParameter, OverrideCompatibilityInfo.Result.INCOMPATIBLE);
190 }
191 }
192
193 for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
194 if (!externalCondition.isOverridable(superDescriptor, subDescriptor)) {
195 return OverrideCompatibilityInfo.externalConditionFailed(externalCondition.getClass());
196 }
197 }
198 }
199 else {
200
201 for (int i = 0; i < superValueParameters.size(); ++i) {
202 JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
203 JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
204 // TODO: compare erasure
205 if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
206 return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameterType, subValueParameterType, OverrideCompatibilityInfo.Result.INCOMPATIBLE);
207 }
208 }
209
210 return OverrideCompatibilityInfo.success();
211
212 }
213
214 // TODO : Default values, varargs etc
215
216 return OverrideCompatibilityInfo.success();
217 }
218
219 private static JetType getUpperBound(JetType type) {
220 if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
221 return type;
222 }
223 else if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) {
224 return ((TypeParameterDescriptor) type.getConstructor().getDeclarationDescriptor()).getUpperBoundsAsType();
225 }
226 else {
227 throw new IllegalStateException("unknown type constructor: " + type.getConstructor().getClass().getName());
228 }
229 }
230
231 public static boolean isReturnTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
232 TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
233 if (typeSubstitutor == null) return false;
234
235 JetType superReturnType = superDescriptor.getReturnType();
236 assert superReturnType != null;
237
238 JetType subReturnType = subDescriptor.getReturnType();
239 assert subReturnType != null;
240
241 JetType substitutedSuperReturnType = typeSubstitutor.substitute(superReturnType, Variance.OUT_VARIANCE);
242 assert substitutedSuperReturnType != null;
243
244 return typeChecker.isSubtypeOf(subReturnType, substitutedSuperReturnType);
245 }
246
247 @Nullable
248 private static TypeSubstitutor prepareTypeSubstitutor(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
249 List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
250 List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
251 if (subTypeParameters.size() != superTypeParameters.size()) return null;
252
253 Map<TypeConstructor, TypeProjection> substitutionContext = Maps.newHashMap();
254 for (int i = 0; i < superTypeParameters.size(); i++) {
255 TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
256 TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
257 substitutionContext.put(
258 superTypeParameter.getTypeConstructor(),
259 new TypeProjection(subTypeParameter.getDefaultType()));
260 }
261 return TypeSubstitutor.create(substitutionContext);
262 }
263
264 public static boolean isPropertyTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull PropertyDescriptor superDescriptor, @NotNull PropertyDescriptor subDescriptor) {
265 TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
266 JetType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getReturnType(), Variance.OUT_VARIANCE);
267 assert substitutedSuperReturnType != null;
268 if (superDescriptor.isVar() && !typeChecker.equalTypes(subDescriptor.getReturnType(), substitutedSuperReturnType)) {
269 return false;
270 }
271
272 return true;
273 }
274
275 /**
276 * Get overridden descriptors that are declarations or delegations.
277 *
278 * @see CallableMemberDescriptor.Kind#isReal()
279 */
280 public static Collection<CallableMemberDescriptor> getOverriddenDeclarations(CallableMemberDescriptor descriptor) {
281 Map<ClassDescriptor, CallableMemberDescriptor> result = Maps.newHashMap();
282 getOverriddenDeclarations(descriptor, result);
283 return result.values();
284 }
285
286 private static void getOverriddenDeclarations(CallableMemberDescriptor descriptor, Map<ClassDescriptor, CallableMemberDescriptor> r) {
287 if (descriptor.getKind().isReal()) {
288 r.put((ClassDescriptor) descriptor.getContainingDeclaration(), descriptor);
289 }
290 else {
291 if (descriptor.getOverriddenDescriptors().isEmpty()) {
292 throw new IllegalStateException();
293 }
294 for (CallableMemberDescriptor overridden : descriptor.getOverriddenDescriptors()) {
295 getOverriddenDeclarations(overridden, r);
296 }
297 }
298 }
299
300 public static void bindOverride(CallableMemberDescriptor fromCurrent, CallableMemberDescriptor fromSupertype) {
301 fromCurrent.addOverriddenDescriptor(fromSupertype);
302
303 for (ValueParameterDescriptor parameterFromCurrent : fromCurrent.getValueParameters()) {
304 assert parameterFromCurrent.getIndex() < fromSupertype.getValueParameters().size()
305 : "An override relation between functions implies that they have the same number of value parameters";
306 ValueParameterDescriptor parameterFromSupertype = fromSupertype.getValueParameters().get(parameterFromCurrent.getIndex());
307 parameterFromCurrent.addOverriddenDescriptor(parameterFromSupertype);
308 }
309 }
310
311 public static class OverrideCompatibilityInfo {
312
313 public enum Result {
314 OVERRIDABLE,
315 INCOMPATIBLE,
316 CONFLICT,
317 }
318
319 private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(Result.OVERRIDABLE, "SUCCESS");
320
321 @NotNull
322 public static OverrideCompatibilityInfo success() {
323 return SUCCESS;
324 }
325
326 @NotNull
327 public static OverrideCompatibilityInfo nameMismatch() {
328 return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "nameMismatch"); // TODO
329 }
330
331 @NotNull
332 public static OverrideCompatibilityInfo typeParameterNumberMismatch() {
333 return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "typeParameterNumberMismatch"); // TODO
334 }
335
336 @NotNull
337 public static OverrideCompatibilityInfo receiverPresenceMismatch() {
338 return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "receiverPresenceMismatch"); // TODO
339 }
340
341 @NotNull
342 public static OverrideCompatibilityInfo valueParameterNumberMismatch() {
343 return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "valueParameterNumberMismatch"); // TODO
344 }
345
346 @NotNull
347 public static OverrideCompatibilityInfo boundsMismatch(TypeParameterDescriptor superTypeParameter, TypeParameterDescriptor subTypeParameter) {
348 return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "boundsMismatch"); // TODO
349 }
350
351 @NotNull
352 public static OverrideCompatibilityInfo valueParameterTypeMismatch(JetType superValueParameter, JetType subValueParameter, Result result) {
353 return new OverrideCompatibilityInfo(result, "valueParameterTypeMismatch"); // TODO
354 }
355
356 @NotNull
357 public static OverrideCompatibilityInfo memberKindMismatch() {
358 return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "memberKindMismatch"); // TODO
359 }
360
361 @NotNull
362 public static OverrideCompatibilityInfo returnTypeMismatch(JetType substitutedSuperReturnType, JetType unsubstitutedSubReturnType) {
363 return new OverrideCompatibilityInfo(Result.CONFLICT, "returnTypeMismatch: " + unsubstitutedSubReturnType + " >< " + substitutedSuperReturnType); // TODO
364 }
365
366 @NotNull
367 public static OverrideCompatibilityInfo varOverriddenByVal() {
368 return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "varOverriddenByVal"); // TODO
369 }
370
371 @NotNull
372 public static OverrideCompatibilityInfo externalConditionFailed(Class<? extends ExternalOverridabilityCondition> conditionClass) {
373 return new OverrideCompatibilityInfo(Result.INCOMPATIBLE, "externalConditionFailed: " + conditionClass.getName()); // TODO
374 }
375
376 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
377
378 private final Result overridable;
379 private final String message;
380
381 public OverrideCompatibilityInfo(Result success, String message) {
382 this.overridable = success;
383 this.message = message;
384 }
385
386 public Result getResult() {
387 return overridable;
388 }
389
390 public String getMessage() {
391 return message;
392 }
393 }
394 }