Overridability and overloadability checks separated
This commit is contained in:
@@ -16,10 +16,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.resolve;
|
package org.jetbrains.jet.lang.resolve;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
|
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.lang.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.INCOMPATIBLE;
|
||||||
|
|
||||||
public class OverloadUtil {
|
public class OverloadUtil {
|
||||||
|
|
||||||
@@ -34,7 +41,7 @@ public class OverloadUtil {
|
|||||||
return OverloadCompatibilityInfo.success();
|
return OverloadCompatibilityInfo.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
OverridingUtil.OverrideCompatibilityInfo overrideCompatibilityInfo = OverridingUtil.DEFAULT.isOverridableByImpl(a, b, false);
|
OverridingUtil.OverrideCompatibilityInfo overrideCompatibilityInfo = isOverloadableBy(a, b);
|
||||||
switch (overrideCompatibilityInfo.getResult()) {
|
switch (overrideCompatibilityInfo.getResult()) {
|
||||||
case OVERRIDABLE:
|
case OVERRIDABLE:
|
||||||
case CONFLICT:
|
case CONFLICT:
|
||||||
@@ -46,6 +53,33 @@ public class OverloadUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static OverridingUtil.OverrideCompatibilityInfo isOverloadableBy(
|
||||||
|
@NotNull CallableDescriptor superDescriptor,
|
||||||
|
@NotNull CallableDescriptor subDescriptor
|
||||||
|
) {
|
||||||
|
OverridingUtil.OverrideCompatibilityInfo
|
||||||
|
receiverAndParameterResult = OverridingUtil.checkReceiverAndParameterCount(superDescriptor, subDescriptor);
|
||||||
|
if (receiverAndParameterResult != null) {
|
||||||
|
return receiverAndParameterResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<JetType> superValueParameters = OverridingUtil.compiledValueParameters(superDescriptor);
|
||||||
|
List<JetType> subValueParameters = OverridingUtil.compiledValueParameters(subDescriptor);
|
||||||
|
|
||||||
|
for (int i = 0; i < superValueParameters.size(); ++i) {
|
||||||
|
JetType superValueParameterType = OverridingUtil.getUpperBound(superValueParameters.get(i));
|
||||||
|
JetType subValueParameterType = OverridingUtil.getUpperBound(subValueParameters.get(i));
|
||||||
|
// TODO: compare erasure
|
||||||
|
if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
|
||||||
|
return OverridingUtil.OverrideCompatibilityInfo
|
||||||
|
.valueParameterTypeMismatch(superValueParameterType, subValueParameterType, INCOMPATIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OverridingUtil.OverrideCompatibilityInfo.success();
|
||||||
|
}
|
||||||
|
|
||||||
private static int braceCount(CallableDescriptor a) {
|
private static int braceCount(CallableDescriptor a) {
|
||||||
if (a instanceof PropertyDescriptor) {
|
if (a instanceof PropertyDescriptor) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -66,6 +66,20 @@ public class OverridingUtil {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public OverrideCompatibilityInfo isOverridableBy(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
public OverrideCompatibilityInfo isOverridableBy(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
||||||
|
return isOverridableBy(superDescriptor, subDescriptor, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public OverrideCompatibilityInfo isOverridableByIncludingReturnType(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
||||||
|
return isOverridableBy(superDescriptor, subDescriptor, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private OverrideCompatibilityInfo isOverridableBy(
|
||||||
|
@NotNull CallableDescriptor superDescriptor,
|
||||||
|
@NotNull CallableDescriptor subDescriptor,
|
||||||
|
boolean checkReturnType
|
||||||
|
) {
|
||||||
if (superDescriptor instanceof FunctionDescriptor) {
|
if (superDescriptor instanceof FunctionDescriptor) {
|
||||||
if (!(subDescriptor instanceof FunctionDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
|
if (!(subDescriptor instanceof FunctionDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
|
||||||
}
|
}
|
||||||
@@ -81,21 +95,95 @@ public class OverridingUtil {
|
|||||||
return OverrideCompatibilityInfo.nameMismatch();
|
return OverrideCompatibilityInfo.nameMismatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
return isOverridableByImpl(superDescriptor, subDescriptor, true, false);
|
OverrideCompatibilityInfo receiverAndParameterResult = checkReceiverAndParameterCount(superDescriptor, subDescriptor);
|
||||||
|
if (receiverAndParameterResult != null) {
|
||||||
|
return receiverAndParameterResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<JetType> superValueParameters = compiledValueParameters(superDescriptor);
|
||||||
|
List<JetType> 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) {
|
||||||
|
JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
|
||||||
|
JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
|
||||||
|
// TODO: compare erasure
|
||||||
|
if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
|
||||||
|
return OverrideCompatibilityInfo.typeParameterNumberMismatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OverrideCompatibilityInfo.valueParameterTypeMismatch(null, null, OverrideCompatibilityInfo.Result.CONFLICT);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>();
|
||||||
|
for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
|
||||||
|
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
||||||
|
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
||||||
|
matchingTypeConstructors.put(superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor());
|
||||||
|
}
|
||||||
|
|
||||||
|
JetTypeChecker.TypeConstructorEquality localEqualityAxioms = new JetTypeChecker.TypeConstructorEquality() {
|
||||||
|
@Override
|
||||||
|
public boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
||||||
|
if (equalityAxioms.equals(a, b)) return true;
|
||||||
|
TypeConstructor img1 = matchingTypeConstructors.get(a);
|
||||||
|
TypeConstructor img2 = matchingTypeConstructors.get(b);
|
||||||
|
if (!(img1 != null && img1.equals(b)) &&
|
||||||
|
!(img2 != null && img2.equals(a))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
|
||||||
|
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
||||||
|
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
||||||
|
|
||||||
|
if (!areTypesEquivalent(superTypeParameter.getUpperBoundsAsType(), subTypeParameter.getUpperBoundsAsType(), localEqualityAxioms)) {
|
||||||
|
return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
|
||||||
|
JetType superValueParameter = superValueParameters.get(i);
|
||||||
|
JetType subValueParameter = subValueParameters.get(i);
|
||||||
|
|
||||||
|
if (!areTypesEquivalent(superValueParameter, subValueParameter, localEqualityAxioms)) {
|
||||||
|
return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameter, subValueParameter, INCOMPATIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkReturnType) {
|
||||||
|
JetType superReturnType = superDescriptor.getReturnType();
|
||||||
|
JetType subReturnType = subDescriptor.getReturnType();
|
||||||
|
|
||||||
|
if (superReturnType != null && subReturnType != null) {
|
||||||
|
boolean bothErrors = subReturnType.isError() && superReturnType.isError();
|
||||||
|
if (!bothErrors && !JetTypeChecker.INSTANCE.isSubtypeOf(subReturnType, superReturnType, localEqualityAxioms)) {
|
||||||
|
return OverrideCompatibilityInfo.returnTypeMismatch(superReturnType, subReturnType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
|
||||||
|
if (!externalCondition.isOverridable(superDescriptor, subDescriptor)) {
|
||||||
|
return OverrideCompatibilityInfo.externalConditionFailed(externalCondition.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OverrideCompatibilityInfo.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Nullable
|
||||||
* @param forOverride true for override, false for overload
|
static OverrideCompatibilityInfo checkReceiverAndParameterCount(
|
||||||
*/
|
CallableDescriptor superDescriptor,
|
||||||
OverrideCompatibilityInfo isOverridableByImpl(
|
CallableDescriptor subDescriptor
|
||||||
@NotNull CallableDescriptor superDescriptor,
|
|
||||||
@NotNull CallableDescriptor subDescriptor,
|
|
||||||
boolean forOverride,
|
|
||||||
boolean checkReturnType
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// TODO : Visibility
|
|
||||||
|
|
||||||
if ((superDescriptor.getReceiverParameter() == null) != (subDescriptor.getReceiverParameter() == null)) {
|
if ((superDescriptor.getReceiverParameter() == null) != (subDescriptor.getReceiverParameter() == null)) {
|
||||||
return OverrideCompatibilityInfo.receiverPresenceMismatch();
|
return OverrideCompatibilityInfo.receiverPresenceMismatch();
|
||||||
}
|
}
|
||||||
@@ -104,100 +192,7 @@ public class OverridingUtil {
|
|||||||
return OverrideCompatibilityInfo.valueParameterNumberMismatch();
|
return OverrideCompatibilityInfo.valueParameterNumberMismatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<JetType> superValueParameters = compiledValueParameters(superDescriptor);
|
return null;
|
||||||
List<JetType> subValueParameters = compiledValueParameters(subDescriptor);
|
|
||||||
|
|
||||||
if (forOverride) {
|
|
||||||
List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
|
|
||||||
List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
|
|
||||||
|
|
||||||
if (superTypeParameters.size() != subTypeParameters.size()) {
|
|
||||||
for (int i = 0; i < superValueParameters.size(); ++i) {
|
|
||||||
JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
|
|
||||||
JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
|
|
||||||
// TODO: compare erasure
|
|
||||||
if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
|
|
||||||
return OverrideCompatibilityInfo.typeParameterNumberMismatch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OverrideCompatibilityInfo.valueParameterTypeMismatch(null, null, OverrideCompatibilityInfo.Result.CONFLICT);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>();
|
|
||||||
for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
|
|
||||||
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
|
||||||
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
|
||||||
matchingTypeConstructors.put(superTypeParameter.getTypeConstructor(), subTypeParameter.getTypeConstructor());
|
|
||||||
}
|
|
||||||
|
|
||||||
JetTypeChecker.TypeConstructorEquality localEqualityAxioms = new JetTypeChecker.TypeConstructorEquality() {
|
|
||||||
@Override
|
|
||||||
public boolean equals(@NotNull TypeConstructor a, @NotNull TypeConstructor b) {
|
|
||||||
if (equalityAxioms.equals(a, b)) return true;
|
|
||||||
TypeConstructor img1 = matchingTypeConstructors.get(a);
|
|
||||||
TypeConstructor img2 = matchingTypeConstructors.get(b);
|
|
||||||
if (!(img1 != null && img1.equals(b)) &&
|
|
||||||
!(img2 != null && img2.equals(a))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0, typeParametersSize = superTypeParameters.size(); i < typeParametersSize; i++) {
|
|
||||||
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
|
||||||
TypeParameterDescriptor subTypeParameter = subTypeParameters.get(i);
|
|
||||||
|
|
||||||
if (!areTypesEquivalent(superTypeParameter.getUpperBoundsAsType(), subTypeParameter.getUpperBoundsAsType(), localEqualityAxioms)) {
|
|
||||||
return OverrideCompatibilityInfo.boundsMismatch(superTypeParameter, subTypeParameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0, unsubstitutedValueParametersSize = superValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
|
|
||||||
JetType superValueParameter = superValueParameters.get(i);
|
|
||||||
JetType subValueParameter = subValueParameters.get(i);
|
|
||||||
|
|
||||||
if (!areTypesEquivalent(superValueParameter, subValueParameter, localEqualityAxioms)) {
|
|
||||||
return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameter, subValueParameter, INCOMPATIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkReturnType) {
|
|
||||||
JetType superReturnType = superDescriptor.getReturnType();
|
|
||||||
JetType subReturnType = subDescriptor.getReturnType();
|
|
||||||
|
|
||||||
if (superReturnType != null &&
|
|
||||||
subReturnType != null &&
|
|
||||||
!areTypesEquivalent(superReturnType, subReturnType, localEqualityAxioms)) {
|
|
||||||
return OverrideCompatibilityInfo.returnTypeMismatch(superReturnType, subReturnType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
|
|
||||||
if (!externalCondition.isOverridable(superDescriptor, subDescriptor)) {
|
|
||||||
return OverrideCompatibilityInfo.externalConditionFailed(externalCondition.getClass());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
for (int i = 0; i < superValueParameters.size(); ++i) {
|
|
||||||
JetType superValueParameterType = getUpperBound(superValueParameters.get(i));
|
|
||||||
JetType subValueParameterType = getUpperBound(subValueParameters.get(i));
|
|
||||||
// TODO: compare erasure
|
|
||||||
if (!JetTypeChecker.INSTANCE.equalTypes(superValueParameterType, subValueParameterType)) {
|
|
||||||
return OverrideCompatibilityInfo.valueParameterTypeMismatch(superValueParameterType, subValueParameterType, INCOMPATIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return OverrideCompatibilityInfo.success();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO : Default values, varargs etc
|
|
||||||
|
|
||||||
return OverrideCompatibilityInfo.success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean areTypesEquivalent(
|
private static boolean areTypesEquivalent(
|
||||||
@@ -212,7 +207,7 @@ public class OverridingUtil {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<JetType> compiledValueParameters(CallableDescriptor callableDescriptor) {
|
static List<JetType> compiledValueParameters(CallableDescriptor callableDescriptor) {
|
||||||
ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
|
ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
|
||||||
ArrayList<JetType> parameters = new ArrayList<JetType>();
|
ArrayList<JetType> parameters = new ArrayList<JetType>();
|
||||||
if (receiverParameter != null) {
|
if (receiverParameter != null) {
|
||||||
@@ -224,7 +219,7 @@ public class OverridingUtil {
|
|||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JetType getUpperBound(JetType type) {
|
static JetType getUpperBound(JetType type) {
|
||||||
if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
|
if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,21 +31,29 @@ public class JetTypeChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
|
public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
// return new TypeCheckingProcedure().run(subtype, supertype);
|
|
||||||
return TYPE_CHECKER.isSubtypeOf(subtype, supertype);
|
return TYPE_CHECKER.isSubtypeOf(subtype, supertype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype, @NotNull final TypeConstructorEquality equalityAxioms) {
|
||||||
|
return createWithAxioms(equalityAxioms).isSubtypeOf(subtype, supertype);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean equalTypes(@NotNull JetType a, @NotNull JetType b) {
|
public boolean equalTypes(@NotNull JetType a, @NotNull JetType b) {
|
||||||
return TYPE_CHECKER.equalTypes(a, b);
|
return TYPE_CHECKER.equalTypes(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equalTypes(@NotNull JetType a, @NotNull JetType b, @NotNull final TypeConstructorEquality equalityAxioms) {
|
public boolean equalTypes(@NotNull JetType a, @NotNull JetType b, @NotNull final TypeConstructorEquality equalityAxioms) {
|
||||||
|
return createWithAxioms(equalityAxioms).equalTypes(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static TypeCheckingProcedure createWithAxioms(@NotNull final TypeConstructorEquality equalityAxioms) {
|
||||||
return new TypeCheckingProcedure(new TypeCheckerTypingConstraints() {
|
return new TypeCheckingProcedure(new TypeCheckerTypingConstraints() {
|
||||||
@Override
|
@Override
|
||||||
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor constructor1, @NotNull TypeConstructor constructor2) {
|
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor constructor1, @NotNull TypeConstructor constructor2) {
|
||||||
return constructor1.equals(constructor2) || equalityAxioms.equals(constructor1, constructor2);
|
return constructor1.equals(constructor2) || equalityAxioms.equals(constructor1, constructor2);
|
||||||
}
|
}
|
||||||
}).equalTypes(a, b);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final TypeCheckingProcedure TYPE_CHECKER = new TypeCheckingProcedure(new TypeCheckerTypingConstraints());
|
private static final TypeCheckingProcedure TYPE_CHECKER = new TypeCheckingProcedure(new TypeCheckerTypingConstraints());
|
||||||
|
|||||||
Reference in New Issue
Block a user