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