diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java index 33f22d6cfaa..6eccea98512 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverloadUtil.java @@ -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 superValueParameters = OverridingUtil.compiledValueParameters(superDescriptor); + List 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; diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index 63b8fcb42de..455c7ff4afc 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -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 superValueParameters = compiledValueParameters(superDescriptor); + List subValueParameters = compiledValueParameters(subDescriptor); + + List superTypeParameters = superDescriptor.getTypeParameters(); + List 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 matchingTypeConstructors = new HashMap(); + 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 superValueParameters = compiledValueParameters(superDescriptor); - List subValueParameters = compiledValueParameters(subDescriptor); - - if (forOverride) { - List superTypeParameters = superDescriptor.getTypeParameters(); - List 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 matchingTypeConstructors = new HashMap(); - 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 compiledValueParameters(CallableDescriptor callableDescriptor) { + static List compiledValueParameters(CallableDescriptor callableDescriptor) { ReceiverParameterDescriptor receiverParameter = callableDescriptor.getReceiverParameter(); ArrayList parameters = new ArrayList(); 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; } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java b/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java index 20ff89f3b9a..28e7d5e2183 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/types/checker/JetTypeChecker.java @@ -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());