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; 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,33 +95,14 @@ 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;
/**
* @param forOverride true for override, false for overload
*/
OverrideCompatibilityInfo isOverridableByImpl(
@NotNull CallableDescriptor superDescriptor,
@NotNull CallableDescriptor subDescriptor,
boolean forOverride,
boolean checkReturnType
) {
// TODO : Visibility
if ((superDescriptor.getReceiverParameter() == null) != (subDescriptor.getReceiverParameter() == null)) {
return OverrideCompatibilityInfo.receiverPresenceMismatch();
}
if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
return OverrideCompatibilityInfo.valueParameterNumberMismatch();
} }
List<JetType> superValueParameters = compiledValueParameters(superDescriptor); List<JetType> superValueParameters = compiledValueParameters(superDescriptor);
List<JetType> subValueParameters = compiledValueParameters(subDescriptor); List<JetType> subValueParameters = compiledValueParameters(subDescriptor);
if (forOverride) {
List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters(); List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters(); List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
@@ -166,12 +161,13 @@ public class OverridingUtil {
JetType superReturnType = superDescriptor.getReturnType(); JetType superReturnType = superDescriptor.getReturnType();
JetType subReturnType = subDescriptor.getReturnType(); JetType subReturnType = subDescriptor.getReturnType();
if (superReturnType != null && if (superReturnType != null && subReturnType != null) {
subReturnType != null && boolean bothErrors = subReturnType.isError() && superReturnType.isError();
!areTypesEquivalent(superReturnType, subReturnType, localEqualityAxioms)) { if (!bothErrors && !JetTypeChecker.INSTANCE.isSubtypeOf(subReturnType, superReturnType, localEqualityAxioms)) {
return OverrideCompatibilityInfo.returnTypeMismatch(superReturnType, subReturnType); return OverrideCompatibilityInfo.returnTypeMismatch(superReturnType, subReturnType);
} }
} }
}
for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) { for (ExternalOverridabilityCondition externalCondition : EXTERNAL_CONDITIONS) {
@@ -179,25 +175,24 @@ public class OverridingUtil {
return OverrideCompatibilityInfo.externalConditionFailed(externalCondition.getClass()); 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(); return OverrideCompatibilityInfo.success();
} }
// TODO : Default values, varargs etc @Nullable
static OverrideCompatibilityInfo checkReceiverAndParameterCount(
CallableDescriptor superDescriptor,
CallableDescriptor subDescriptor
) {
if ((superDescriptor.getReceiverParameter() == null) != (subDescriptor.getReceiverParameter() == null)) {
return OverrideCompatibilityInfo.receiverPresenceMismatch();
}
return OverrideCompatibilityInfo.success(); if (superDescriptor.getValueParameters().size() != subDescriptor.getValueParameters().size()) {
return OverrideCompatibilityInfo.valueParameterNumberMismatch();
}
return null;
} }
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());