Overridability and overloadability checks separated

This commit is contained in:
Andrey Breslav
2014-05-30 16:31:36 +04:00
parent 3f151a022e
commit 9cfbfd2806
3 changed files with 150 additions and 113 deletions
@@ -16,10 +16,17 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
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 {
@@ -34,7 +41,7 @@ public class OverloadUtil {
return OverloadCompatibilityInfo.success();
}
OverridingUtil.OverrideCompatibilityInfo overrideCompatibilityInfo = OverridingUtil.DEFAULT.isOverridableByImpl(a, b, false);
OverridingUtil.OverrideCompatibilityInfo overrideCompatibilityInfo = isOverloadableBy(a, b);
switch (overrideCompatibilityInfo.getResult()) {
case OVERRIDABLE:
case CONFLICT:
@@ -45,7 +52,34 @@ public class OverloadUtil {
throw new IllegalStateException();
}
}
@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) {
if (a instanceof PropertyDescriptor) {
return 0;
@@ -66,6 +66,20 @@ public class OverridingUtil {
@NotNull
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 (!(subDescriptor instanceof FunctionDescriptor)) return OverrideCompatibilityInfo.memberKindMismatch();
}
@@ -81,21 +95,95 @@ public class OverridingUtil {
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();
}
/**
* @param forOverride true for override, false for overload
*/
OverrideCompatibilityInfo isOverridableByImpl(
@NotNull CallableDescriptor superDescriptor,
@NotNull CallableDescriptor subDescriptor,
boolean forOverride,
boolean checkReturnType
@Nullable
static OverrideCompatibilityInfo checkReceiverAndParameterCount(
CallableDescriptor superDescriptor,
CallableDescriptor subDescriptor
) {
// TODO : Visibility
if ((superDescriptor.getReceiverParameter() == null) != (subDescriptor.getReceiverParameter() == null)) {
return OverrideCompatibilityInfo.receiverPresenceMismatch();
}
@@ -104,100 +192,7 @@ public class OverridingUtil {
return OverrideCompatibilityInfo.valueParameterNumberMismatch();
}
List<JetType> superValueParameters = compiledValueParameters(superDescriptor);
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();
return null;
}
private static boolean areTypesEquivalent(
@@ -212,7 +207,7 @@ public class OverridingUtil {
return true;
}
private static List<JetType> compiledValueParameters(CallableDescriptor callableDescriptor) {
static List<JetType> compiledValueParameters(CallableDescriptor callableDescriptor) {
ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter();
ArrayList<JetType> parameters = new ArrayList<JetType>();
if (receiverParameter != null) {
@@ -224,7 +219,7 @@ public class OverridingUtil {
return parameters;
}
private static JetType getUpperBound(JetType type) {
static JetType getUpperBound(JetType type) {
if (type.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor) {
return type;
}
@@ -31,21 +31,29 @@ public class JetTypeChecker {
}
public boolean isSubtypeOf(@NotNull JetType subtype, @NotNull JetType supertype) {
// return new TypeCheckingProcedure().run(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) {
return TYPE_CHECKER.equalTypes(a, b);
}
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() {
@Override
public boolean assertEqualTypeConstructors(@NotNull TypeConstructor constructor1, @NotNull TypeConstructor constructor2) {
return constructor1.equals(constructor2) || equalityAxioms.equals(constructor1, constructor2);
}
}).equalTypes(a, b);
});
}
private static final TypeCheckingProcedure TYPE_CHECKER = new TypeCheckingProcedure(new TypeCheckerTypingConstraints());