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("No overridden descriptors found for (fake override) " + descriptor); 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 }