@NotNull public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions( @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean checkReturnType) { OverrideCompatibilityInfo basicOverridability = getBasicOverridabilityProblem(superDescriptor, subDescriptor); if (basicOverridability != null) return basicOverridability; List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor); List<KotlinType> subValueParameters = compiledValueParameters(subDescriptor); List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters(); List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters(); if (superTypeParameters.size() != subTypeParameters.size()) { for (int i = 0; i < superValueParameters.size(); ++i) { // TODO: compare erasure if (!KotlinTypeChecker.DEFAULT.equalTypes( superValueParameters.get(i), subValueParameters.get(i))) { return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch"); } } return OverrideCompatibilityInfo.conflict("Type parameter number mismatch"); } KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters); for (int i = 0; i < superTypeParameters.size(); i++) { if (!areTypeParametersEquivalent( superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) { return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch"); } } for (int i = 0; i < superValueParameters.size(); i++) { if (!areTypesEquivalent( superValueParameters.get(i), subValueParameters.get(i), typeChecker)) { return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch"); } } if (checkReturnType) { KotlinType superReturnType = superDescriptor.getReturnType(); KotlinType subReturnType = subDescriptor.getReturnType(); if (superReturnType != null && subReturnType != null) { boolean bothErrors = subReturnType.isError() && superReturnType.isError(); if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) { return OverrideCompatibilityInfo.conflict("Return type mismatch"); } } } return OverrideCompatibilityInfo.success(); }
@NotNull private OverrideCompatibilityInfo isOverridableBy( @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean checkReturnType) { for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) { ExternalOverridabilityCondition.Result result = externalCondition.isOverridable(superDescriptor, subDescriptor); switch (result) { case OVERRIDABLE: return OverrideCompatibilityInfo.success(); case CONFLICT: return OverrideCompatibilityInfo.conflict("External condition failed"); case INCOMPATIBLE: return OverrideCompatibilityInfo.incompatible("External condition"); case UNKNOWN: // do nothing // go to the next external condition or default override check } } return isOverridableByWithoutExternalConditions( superDescriptor, subDescriptor, checkReturnType); }
@NotNull public OverrideCompatibilityInfo isOverridableByWithoutExternalConditions( @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, boolean checkReturnType) { if (superDescriptor instanceof FunctionDescriptor && !(subDescriptor instanceof FunctionDescriptor) || superDescriptor instanceof PropertyDescriptor && !(subDescriptor instanceof PropertyDescriptor)) { return OverrideCompatibilityInfo.incompatible("Member kind mismatch"); } if (!(superDescriptor instanceof FunctionDescriptor) && !(superDescriptor instanceof PropertyDescriptor)) { throw new IllegalArgumentException( "This type of CallableDescriptor cannot be checked for overridability: " + superDescriptor); } // TODO: check outside of this method if (!superDescriptor.getName().equals(subDescriptor.getName())) { return OverrideCompatibilityInfo.incompatible("Name mismatch"); } OverrideCompatibilityInfo receiverAndParameterResult = checkReceiverAndParameterCount(superDescriptor, subDescriptor); if (receiverAndParameterResult != null) { return receiverAndParameterResult; } List<KotlinType> superValueParameters = compiledValueParameters(superDescriptor); List<KotlinType> subValueParameters = compiledValueParameters(subDescriptor); List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters(); List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters(); if (superTypeParameters.size() != subTypeParameters.size()) { for (int i = 0; i < superValueParameters.size(); ++i) { // TODO: compare erasure if (!KotlinTypeChecker.DEFAULT.equalTypes( superValueParameters.get(i), subValueParameters.get(i))) { return OverrideCompatibilityInfo.incompatible("Type parameter number mismatch"); } } return OverrideCompatibilityInfo.conflict("Type parameter number mismatch"); } KotlinTypeChecker typeChecker = createTypeChecker(superTypeParameters, subTypeParameters); for (int i = 0; i < superTypeParameters.size(); i++) { if (!areTypeParametersEquivalent( superTypeParameters.get(i), subTypeParameters.get(i), typeChecker)) { return OverrideCompatibilityInfo.incompatible("Type parameter bounds mismatch"); } } for (int i = 0; i < superValueParameters.size(); i++) { if (!areTypesEquivalent( superValueParameters.get(i), subValueParameters.get(i), typeChecker)) { return OverrideCompatibilityInfo.incompatible("Value parameter type mismatch"); } } if (checkReturnType) { KotlinType superReturnType = superDescriptor.getReturnType(); KotlinType subReturnType = subDescriptor.getReturnType(); if (superReturnType != null && subReturnType != null) { boolean bothErrors = subReturnType.isError() && superReturnType.isError(); if (!bothErrors && !typeChecker.isSubtypeOf(subReturnType, superReturnType)) { return OverrideCompatibilityInfo.conflict("Return type mismatch"); } } } return OverrideCompatibilityInfo.success(); }
@NotNull public OverrideCompatibilityInfo isOverridableBy( @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor, @Nullable ClassDescriptor subClassDescriptor, boolean checkReturnType) { OverrideCompatibilityInfo basicResult = isOverridableByWithoutExternalConditions(superDescriptor, subDescriptor, checkReturnType); boolean wasSuccess = basicResult.getResult() == OVERRIDABLE; for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) { // Do not run CONFLICTS_ONLY while there was no success if (externalCondition.getContract() == ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY) continue; if (wasSuccess && externalCondition.getContract() == ExternalOverridabilityCondition.Contract.SUCCESS_ONLY) continue; ExternalOverridabilityCondition.Result result = externalCondition.isOverridable(superDescriptor, subDescriptor, subClassDescriptor); switch (result) { case OVERRIDABLE: wasSuccess = true; break; case CONFLICT: return OverrideCompatibilityInfo.conflict("External condition failed"); case INCOMPATIBLE: return OverrideCompatibilityInfo.incompatible("External condition"); case UNKNOWN: // do nothing // go to the next external condition or default override check } } if (!wasSuccess) { return basicResult; } // Search for conflicts from external conditions for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) { // Run all conditions that was not run before (i.e. CONFLICTS_ONLY) if (externalCondition.getContract() != ExternalOverridabilityCondition.Contract.CONFLICTS_ONLY) continue; ExternalOverridabilityCondition.Result result = externalCondition.isOverridable(superDescriptor, subDescriptor, subClassDescriptor); switch (result) { case CONFLICT: return OverrideCompatibilityInfo.conflict("External condition failed"); case INCOMPATIBLE: return OverrideCompatibilityInfo.incompatible("External condition"); case OVERRIDABLE: throw new IllegalStateException( "Contract violation in " + externalCondition.getClass().getName() + " condition. It's not supposed to end with success"); case UNKNOWN: // do nothing // go to the next external condition or default override check } } return OverrideCompatibilityInfo.success(); }