diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 81ed3b21b2d..96f39e7b050 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -329,6 +329,15 @@ public interface Errors { DiagnosticFactory2 PROPERTY_TYPE_MISMATCH_ON_INHERITANCE = DiagnosticFactory2.create(ERROR, DECLARATION_NAME); + DiagnosticFactory2 OVERRIDING_FINAL_MEMBER_BY_DELEGATION = + DiagnosticFactory2.create(ERROR, DECLARATION_NAME); + DiagnosticFactory2 RETURN_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION = + DiagnosticFactory2.create(ERROR, DECLARATION_NAME); + DiagnosticFactory2 PROPERTY_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION = + DiagnosticFactory2.create(ERROR, DECLARATION_NAME); + DiagnosticFactory2 VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION = + DiagnosticFactory2.create(ERROR, DECLARATION_NAME); + DiagnosticFactory2 ABSTRACT_MEMBER_NOT_IMPLEMENTED = DiagnosticFactory2.create(ERROR, DECLARATION_NAME); DiagnosticFactory2 ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED = diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 3504317d080..c1736a1a028 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -563,6 +563,15 @@ public class DefaultErrorMessages { MAP.put(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, "''{0}'' clashes with ''{1}'': property types are incompatible", SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); + MAP.put(OVERRIDING_FINAL_MEMBER_BY_DELEGATION, "''{0}'' implicitly overrides a final member ''{1}'' by delegation", + SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); + MAP.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION, "Return type of ''{0}'' doesn't match ''{1}'' implicitly overridden by delegation", + SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); + MAP.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION, "Property type of ''{0}'' doesn't match ''{1}'' implicitly overridden by delegation", + SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); + MAP.put(VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, "val-property ''{0}'' implicitly overrides a var-property ''{1}'' by delegation", + SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); + MAP.put(VAR_OVERRIDDEN_BY_VAL, "Var-property {0} cannot be overridden by val-property {1}", FQ_NAMES_IN_TYPES, FQ_NAMES_IN_TYPES); MAP.put(ABSTRACT_MEMBER_NOT_IMPLEMENTED, "{0} must be declared abstract or implement abstract member {1}", RENDER_CLASS_OR_OBJECT, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverrideResolver.java index b66b7b6a1dd..0a8c6ff4fb3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverrideResolver.java @@ -25,6 +25,7 @@ import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.LinkedMultiMap; import com.intellij.util.containers.MultiMap; +import com.intellij.util.containers.SmartHashSet; import com.intellij.util.containers.hash.EqualityPolicy; import kotlin.Unit; import kotlin.jvm.functions.Function1; @@ -32,6 +33,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.ReadOnly; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2; +import org.jetbrains.kotlin.diagnostics.DiagnosticFactoryWithPsiElement; import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.name.Name; @@ -263,144 +266,229 @@ public class OverrideResolver { checkOverrideForMember(member); } - // Check if everything that must be overridden, actually is - // More than one implementation or no implementations at all - final Set abstractNoImpl = Sets.newLinkedHashSet(); - final Set manyImpl = Sets.newLinkedHashSet(); - final Set abstractInBaseClassNoImpl = Sets.newLinkedHashSet(); - final Set conflictingInterfaceOverrides = Sets.newLinkedHashSet(); + CollectErrorInformationForInheritedMembersStrategy inheritedMemberErrors = + new CollectErrorInformationForInheritedMembersStrategy(klass, classDescriptor); - checkInheritedSignatures( - classDescriptor, - new CheckInheritedSignaturesReportingStrategy() { - private boolean returnTypeMismatch = false; - private boolean propertyTypeMismatch = false; - - @Override - public void abstractMemberNoImpl(CallableMemberDescriptor descriptor) { - abstractNoImpl.add(descriptor); - } - - @Override - public void abstractBaseClassMemberNoImpl(CallableMemberDescriptor descriptor) { - abstractInBaseClassNoImpl.add(descriptor); - } - - @Override - public void manyImplMemberNoImpl(CallableMemberDescriptor descriptor) { - manyImpl.add(descriptor); - } - - @Override - public void conflictingMemberFromInterface(CallableMemberDescriptor descriptor) { - conflictingInterfaceOverrides.add(descriptor); - } - - @Override - public void clashingWithReturnType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) { - if (!returnTypeMismatch) { - returnTypeMismatch = true; - trace.report(RETURN_TYPE_MISMATCH_ON_INHERITANCE.on(klass, descriptor1, descriptor2)); - } - } - - @Override - public void clashingWithPropertyType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) { - if (!propertyTypeMismatch) { - propertyTypeMismatch = true; - trace.report(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE.on(klass, descriptor1, descriptor2)); - } - } - }); - - if (!classCanHaveAbstractMembers(classDescriptor)) { - if (!abstractInBaseClassNoImpl.isEmpty()) { - trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.iterator().next())); - } - else if (!abstractNoImpl.isEmpty()) { - trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.iterator().next())); - } - } - - if (!conflictingInterfaceOverrides.isEmpty()) { - trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceOverrides.iterator().next())); - } - else if (!manyImpl.isEmpty()) { - trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, manyImpl.iterator().next())); - } + checkInheritedAndDelegatedSignatures(classDescriptor, inheritedMemberErrors, inheritedMemberErrors); + inheritedMemberErrors.doReportErrors(); } @NotNull public static Set getMissingImplementations(@NotNull ClassDescriptor classDescriptor) { CollectMissingImplementationsStrategy collector = new CollectMissingImplementationsStrategy(); - checkInheritedSignatures(classDescriptor, collector); + checkInheritedAndDelegatedSignatures(classDescriptor, collector, null); return collector.shouldImplement; } - private interface CheckInheritedSignaturesReportingStrategy { - void abstractMemberNoImpl(CallableMemberDescriptor descriptor); - void abstractBaseClassMemberNoImpl(CallableMemberDescriptor descriptor); - void manyImplMemberNoImpl(CallableMemberDescriptor descriptor); - void conflictingMemberFromInterface(CallableMemberDescriptor descriptor); - void clashingWithReturnType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2); - void clashingWithPropertyType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2); + private interface CheckInheritedSignaturesReportStrategy { + void abstractMemberNotImplemented(CallableMemberDescriptor descriptor); + void abstractBaseClassMemberNotImplemented(CallableMemberDescriptor descriptor); + void multipleImplementationsMemberNotImplemented(CallableMemberDescriptor descriptor); + void conflictingInterfaceMemberNotImplemented(CallableMemberDescriptor descriptor); + void returnTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2); + void propertyTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2); } - private static class CollectMissingImplementationsStrategy implements CheckInheritedSignaturesReportingStrategy { + private static class CollectMissingImplementationsStrategy implements CheckInheritedSignaturesReportStrategy { private Set shouldImplement = new LinkedHashSet(); @Override - public void abstractMemberNoImpl(CallableMemberDescriptor descriptor) { + public void abstractMemberNotImplemented(CallableMemberDescriptor descriptor) { shouldImplement.add(descriptor); } @Override - public void abstractBaseClassMemberNoImpl(CallableMemberDescriptor descriptor) { + public void abstractBaseClassMemberNotImplemented(CallableMemberDescriptor descriptor) { // don't care } @Override - public void manyImplMemberNoImpl(CallableMemberDescriptor descriptor) { + public void multipleImplementationsMemberNotImplemented(CallableMemberDescriptor descriptor) { shouldImplement.add(descriptor); } @Override - public void conflictingMemberFromInterface(CallableMemberDescriptor descriptor) { + public void conflictingInterfaceMemberNotImplemented(CallableMemberDescriptor descriptor) { // don't care } @Override - public void clashingWithReturnType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) { + public void returnTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) { // don't care } @Override - public void clashingWithPropertyType(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) { + public void propertyTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) { // don't care } } - private static void checkInheritedSignatures( - @NotNull ClassDescriptor classDescriptor, - @NotNull CheckInheritedSignaturesReportingStrategy reportingStrategy - ) { - for (DeclarationDescriptor member : DescriptorUtils.getAllDescriptors(classDescriptor.getDefaultType().getMemberScope())) { - if (member instanceof CallableMemberDescriptor) { - checkInheritedSignatures((CallableMemberDescriptor) member, reportingStrategy); + private class CollectErrorInformationForInheritedMembersStrategy + implements CheckInheritedSignaturesReportStrategy, CheckOverrideReportStrategy { + private final KtClassOrObject klass; + private final ClassDescriptor classDescriptor; + + private final Set abstractNoImpl = Sets.newLinkedHashSet(); + private final Set multipleImplementations = Sets.newLinkedHashSet(); + private final Set abstractInBaseClassNoImpl = Sets.newLinkedHashSet(); + private final Set conflictingInterfaceMembers = Sets.newLinkedHashSet(); + private final Set conflictingReturnTypes = Sets.newHashSet(); + + private final Set onceErrorsReported = new SmartHashSet(); + + public CollectErrorInformationForInheritedMembersStrategy( + @NotNull KtClassOrObject klass, + @NotNull ClassDescriptor classDescriptor + ) { + this.klass = klass; + this.classDescriptor = classDescriptor; + } + + @Override + public void abstractMemberNotImplemented(CallableMemberDescriptor descriptor) { + abstractNoImpl.add(descriptor); + } + + @Override + public void abstractBaseClassMemberNotImplemented(CallableMemberDescriptor descriptor) { + abstractInBaseClassNoImpl.add(descriptor); + } + + @Override + public void multipleImplementationsMemberNotImplemented(CallableMemberDescriptor descriptor) { + multipleImplementations.add(descriptor); + } + + @Override + public void conflictingInterfaceMemberNotImplemented(CallableMemberDescriptor descriptor) { + conflictingInterfaceMembers.add(descriptor); + } + + @Override + public void returnTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) { + conflictingReturnTypes.add(descriptor1); + conflictingReturnTypes.add(descriptor2); + + reportInheritanceConflictIfRequired(RETURN_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2); + } + + @Override + public void propertyTypeMismatchOnInheritance(CallableMemberDescriptor descriptor1, CallableMemberDescriptor descriptor2) { + conflictingReturnTypes.add(descriptor1); + conflictingReturnTypes.add(descriptor2); + + reportInheritanceConflictIfRequired(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2); + } + + private void reportInheritanceConflictIfRequired( + @NotNull DiagnosticFactory2 diagnosticFactory, + @NotNull CallableMemberDescriptor descriptor1, + @NotNull CallableMemberDescriptor descriptor2 + ) { + if (!onceErrorsReported.contains(diagnosticFactory)) { + onceErrorsReported.add(diagnosticFactory); + trace.report(diagnosticFactory.on(klass, descriptor1, descriptor2)); + } + } + + @Override + public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { + reportDelegationProblemIfRequired(OVERRIDING_FINAL_MEMBER_BY_DELEGATION, overriding, overridden); + } + + @Override + public void returnTypeMismatchOnOverride( + @NotNull CallableMemberDescriptor overriding, + @NotNull CallableMemberDescriptor overridden + ) { + conflictingReturnTypes.add(overridden); + reportDelegationProblemIfRequired(RETURN_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION, overriding, overridden); + } + + @Override + public void propertyTypeMismatchOnOverride( + @NotNull CallableMemberDescriptor overriding, + @NotNull CallableMemberDescriptor overridden + ) { + conflictingReturnTypes.add(overridden); + reportDelegationProblemIfRequired(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE_BY_DELEGATION, overriding, overridden); + } + + @Override + public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { + reportDelegationProblemIfRequired(VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, overriding, overridden); + } + + private void reportDelegationProblemIfRequired( + @NotNull DiagnosticFactory2 diagnosticFactory, + @NotNull CallableMemberDescriptor delegate, + @NotNull CallableMemberDescriptor overridden + ) { + assert delegate.getKind() == DELEGATION : "Delegate expected, got " + delegate + " of kind " + delegate.getKind(); + + if (!onceErrorsReported.contains(diagnosticFactory)) { + onceErrorsReported.add(diagnosticFactory); + trace.report(diagnosticFactory.on(klass, delegate, overridden)); + } + } + + @Override + public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden) { + assert overriding.getKind() == DELEGATION : "Delegate expected, got " + overriding + " of kind " + overriding.getKind(); + assert overriding.getKind() != DELEGATION : "Delegated member can't override an invisible member; " + invisibleOverridden; + } + + @Override + public void nothingToOverride(@NotNull CallableMemberDescriptor overriding) { + assert overriding.getKind() == DELEGATION : "Delegate expected, got " + overriding + " of kind " + overriding.getKind(); + assert overriding.getKind() != DELEGATION : "Delegated member can't override nothing; " + overriding; + } + + void doReportErrors() { + if (!classCanHaveAbstractMembers(classDescriptor)) { + if (!abstractInBaseClassNoImpl.isEmpty()) { + trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.iterator().next())); + } + else if (!abstractNoImpl.isEmpty()) { + trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.iterator().next())); + } + } + + conflictingInterfaceMembers.removeAll(conflictingReturnTypes); + multipleImplementations.removeAll(conflictingReturnTypes); + if (!conflictingInterfaceMembers.isEmpty()) { + trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceMembers.iterator().next())); + } + else if (!multipleImplementations.isEmpty()) { + trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, multipleImplementations.iterator().next())); } } } - private static void checkInheritedSignatures( - @NotNull CallableMemberDescriptor descriptor, - @NotNull CheckInheritedSignaturesReportingStrategy reportingStrategy + private static void checkInheritedAndDelegatedSignatures( + @NotNull ClassDescriptor classDescriptor, + @NotNull CheckInheritedSignaturesReportStrategy inheritedReportStrategy, + @Nullable CheckOverrideReportStrategy overrideReportStrategyForDelegates ) { - if (descriptor.getKind().isReal()) return; + for (DeclarationDescriptor member : DescriptorUtils.getAllDescriptors(classDescriptor.getDefaultType().getMemberScope())) { + if (member instanceof CallableMemberDescriptor) { + checkInheritedAndDelegatedSignatures((CallableMemberDescriptor) member, inheritedReportStrategy, overrideReportStrategyForDelegates); + } + } + } + + private static void checkInheritedAndDelegatedSignatures( + @NotNull CallableMemberDescriptor descriptor, + @NotNull CheckInheritedSignaturesReportStrategy reportingStrategy, + @Nullable CheckOverrideReportStrategy overrideReportStrategyForDelegates + ) { + CallableMemberDescriptor.Kind kind = descriptor.getKind(); + if (kind != FAKE_OVERRIDE && kind != DELEGATION) return; if (descriptor.getVisibility() == Visibilities.INVISIBLE_FAKE) return; Collection directOverridden = descriptor.getOverriddenDescriptors(); if (directOverridden.size() == 0) { - throw new IllegalStateException("A 'fake override' " + descriptor.getName().asString() + " must override something"); + throw new IllegalStateException(kind + " " + descriptor.getName().asString() + " must override something"); } // collects map from the directly overridden descriptor to the set of declarations: @@ -415,39 +503,55 @@ public class OverrideResolver { Set relevantDirectlyOverridden = getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations); - checkInheritedSignaturesForFakeOverride(descriptor, relevantDirectlyOverridden, reportingStrategy); + checkInheritedDescriptorsGroup(relevantDirectlyOverridden, reportingStrategy); - collectJava8MissingOverrides(relevantDirectlyOverridden, reportingStrategy); + if (kind == DELEGATION) { + if (overrideReportStrategyForDelegates != null) { + checkOverridesForMember(descriptor, relevantDirectlyOverridden, overrideReportStrategyForDelegates); + } + } + + if (kind != DELEGATION) { + checkMissingOverridesByJava8Restrictions(descriptor, relevantDirectlyOverridden, reportingStrategy); + } List implementations = collectImplementations(relevantDirectlyOverridden); - if (implementations.size() == 1 && isReturnTypeOkForOverride(descriptor, implementations.get(0))) return; + + int numImplementations = implementations.size(); + + if (numImplementations == 1 && isReturnTypeOkForOverride(descriptor, implementations.get(0))) return; List abstractOverridden = new ArrayList(allFilteredOverriddenDeclarations.size()); List concreteOverridden = new ArrayList(allFilteredOverriddenDeclarations.size()); filterNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, abstractOverridden, concreteOverridden); - if (implementations.isEmpty()) { - for (CallableMemberDescriptor member : abstractOverridden) { - reportingStrategy.abstractMemberNoImpl(member); + if (numImplementations == 0) { + if (kind != DELEGATION) { + for (CallableMemberDescriptor member : abstractOverridden) { + reportingStrategy.abstractMemberNotImplemented(member); + } } } - else if (implementations.size() > 1) { + else if (numImplementations > 1) { for (CallableMemberDescriptor member : concreteOverridden) { - reportingStrategy.manyImplMemberNoImpl(member); + reportingStrategy.multipleImplementationsMemberNotImplemented(member); } } else { - List membersWithMoreSpecificReturnType = - collectAbstractMethodsWithMoreSpecificReturnType(abstractOverridden, implementations.get(0)); - for (CallableMemberDescriptor member : membersWithMoreSpecificReturnType) { - reportingStrategy.abstractMemberNoImpl(member); + if (kind != DELEGATION) { + List membersWithMoreSpecificReturnType = + collectAbstractMethodsWithMoreSpecificReturnType(abstractOverridden, implementations.get(0)); + for (CallableMemberDescriptor member : membersWithMoreSpecificReturnType) { + reportingStrategy.abstractMemberNotImplemented(member); + } } } } - private static void collectJava8MissingOverrides( + private static void checkMissingOverridesByJava8Restrictions( + @NotNull CallableMemberDescriptor descriptor, @NotNull Set relevantDirectlyOverridden, - @NotNull CheckInheritedSignaturesReportingStrategy reportingStrategy + @NotNull CheckInheritedSignaturesReportStrategy reportingStrategy ) { // Java 8: // -- class should implement an abstract member of a super-class, @@ -479,12 +583,11 @@ public class OverrideResolver { } if (overridesAbstractInBaseClass != null) { - reportingStrategy.abstractBaseClassMemberNoImpl(overridesAbstractInBaseClass); + reportingStrategy.abstractBaseClassMemberNotImplemented(overridesAbstractInBaseClass); } - if (!overridesClassMember && overridesNonAbstractInterfaceMember && overriddenInterfaceMembers.size() > 1) { for (CallableMemberDescriptor member : overriddenInterfaceMembers) { - reportingStrategy.conflictingMemberFromInterface(member); + reportingStrategy.conflictingInterfaceMemberNotImplemented(member); } } } @@ -634,17 +737,12 @@ public class OverrideResolver { } private interface CheckOverrideReportStrategy { - void overridingFinalMember(@NotNull CallableMemberDescriptor overridden); - - void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden); - - void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden); - - void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden); - - void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden); - - void nothingToOverride(); + void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden); + void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden); + void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden); + void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden); + void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden); + void nothingToOverride(@NotNull CallableMemberDescriptor overriding); } private void checkOverrideForMember(@NotNull final CallableMemberDescriptor declared) { @@ -675,7 +773,7 @@ public class OverrideResolver { private boolean kindMismatchError = false; @Override - public void overridingFinalMember(@NotNull CallableMemberDescriptor overridden) { + public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { if (!finalOverriddenError) { finalOverriddenError = true; trace.report(OVERRIDING_FINAL_MEMBER.on(member, overridden, overridden.getContainingDeclaration())); @@ -683,7 +781,7 @@ public class OverrideResolver { } @Override - public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) { + public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { if (!typeMismatchError) { typeMismatchError = true; trace.report(RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden)); @@ -691,7 +789,7 @@ public class OverrideResolver { } @Override - public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) { + public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { if (!typeMismatchError) { typeMismatchError = true; trace.report(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden)); @@ -699,7 +797,7 @@ public class OverrideResolver { } @Override - public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) { + public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { if (!kindMismatchError) { kindMismatchError = true; trace.report(VAR_OVERRIDDEN_BY_VAL.on(member, (PropertyDescriptor) declared, (PropertyDescriptor) overridden)); @@ -707,12 +805,12 @@ public class OverrideResolver { } @Override - public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden) { + public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden) { trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverridden)); } @Override - public void nothingToOverride() { + public void nothingToOverride(@NotNull CallableMemberDescriptor overriding) { trace.report(NOTHING_TO_OVERRIDE.on(member, declared)); } }); @@ -723,33 +821,28 @@ public class OverrideResolver { } } - private static void checkInheritedSignaturesForFakeOverride( - @NotNull CallableMemberDescriptor fakeOverride, - @NotNull Collection relevantDirectlyOverridden, - @NotNull CheckInheritedSignaturesReportingStrategy reportingStrategy + private static void checkInheritedDescriptorsGroup( + @NotNull Collection inheritedDescriptors, + @NotNull CheckInheritedSignaturesReportStrategy reportingStrategy ) { - assert fakeOverride.getKind() == FAKE_OVERRIDE - : "Fake override expected; actual: " + fakeOverride + " of kind " + fakeOverride.getKind(); - // FIXME This algorithm depends on transitiveness of sub-typing relation, which is broken in presence of flexible types. - // See override/clashesOnInheritance/flexibleReturnType.kt. - if (relevantDirectlyOverridden.size() > 1) { - Iterator overriddenIterator = relevantDirectlyOverridden.iterator(); - CallableMemberDescriptor mostSpecificOverridden = overriddenIterator.next(); - while (overriddenIterator.hasNext()) { - CallableMemberDescriptor overriddenDescriptor = overriddenIterator.next(); - if (OverridingUtil.isMoreSpecific(overriddenDescriptor, mostSpecificOverridden)) { - mostSpecificOverridden = overriddenDescriptor; + if (inheritedDescriptors.size() > 1) { + Iterator inheritedIterator = inheritedDescriptors.iterator(); + CallableMemberDescriptor mostSpecificInherited = inheritedIterator.next(); + while (inheritedIterator.hasNext()) { + CallableMemberDescriptor overriddenDescriptor = inheritedIterator.next(); + if (OverridingUtil.isMoreSpecific(overriddenDescriptor, mostSpecificInherited)) { + mostSpecificInherited = overriddenDescriptor; } } - for (CallableMemberDescriptor overriddenDescriptor : relevantDirectlyOverridden) { - if (!OverridingUtil.isMoreSpecific(mostSpecificOverridden, overriddenDescriptor)) { - if (overriddenDescriptor instanceof PropertyDescriptor) { - reportingStrategy.clashingWithPropertyType(mostSpecificOverridden, overriddenDescriptor); + for (CallableMemberDescriptor inheritedDescriptor : inheritedDescriptors) { + if (!OverridingUtil.isMoreSpecific(mostSpecificInherited, inheritedDescriptor)) { + if (inheritedDescriptor instanceof PropertyDescriptor) { + reportingStrategy.propertyTypeMismatchOnInheritance(mostSpecificInherited, inheritedDescriptor); } else { - reportingStrategy.clashingWithReturnType(mostSpecificOverridden, overriddenDescriptor); + reportingStrategy.returnTypeMismatchOnInheritance(mostSpecificInherited, inheritedDescriptor); } } } @@ -763,25 +856,7 @@ public class OverrideResolver { ) { Collection overriddenDescriptors = declared.getOverriddenDescriptors(); - for (CallableMemberDescriptor overridden : overriddenDescriptors) { - if (overridden == null) continue; - - if (!overridden.getModality().isOverridable()) { - reportError.overridingFinalMember(overridden); - } - - if (declared instanceof PropertyDescriptor && - !isPropertyTypeOkForOverride((PropertyDescriptor) overridden, (PropertyDescriptor) declared)) { - reportError.propertyTypeMismatchOnOverride(overridden); - } - else if (!isReturnTypeOkForOverride(overridden, declared)) { - reportError.returnTypeMismatchOnOverride(overridden); - } - - if (checkPropertyKind(overridden, true) && checkPropertyKind(declared, false)) { - reportError.varOverriddenByVal(overridden); - } - } + checkOverridesForMember(declared, overriddenDescriptors, reportError); if (checkIfOverridesNothing && overriddenDescriptors.isEmpty()) { DeclarationDescriptor containingDeclaration = declared.getContainingDeclaration(); @@ -790,10 +865,36 @@ public class OverrideResolver { CallableMemberDescriptor invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass); if (invisibleOverriddenDescriptor != null) { - reportError.cannotOverrideInvisibleMember(invisibleOverriddenDescriptor); + reportError.cannotOverrideInvisibleMember(declared, invisibleOverriddenDescriptor); } else { - reportError.nothingToOverride(); + reportError.nothingToOverride(declared); + } + } + } + + private static void checkOverridesForMember( + CallableMemberDescriptor memberDescriptor, + Collection overriddenDescriptors, + @NotNull CheckOverrideReportStrategy reportError + ) { + for (CallableMemberDescriptor overridden : overriddenDescriptors) { + if (overridden == null) continue; + + if (!overridden.getModality().isOverridable()) { + reportError.overridingFinalMember(memberDescriptor, overridden); + } + + if (memberDescriptor instanceof PropertyDescriptor && + !isPropertyTypeOkForOverride((PropertyDescriptor) overridden, (PropertyDescriptor) memberDescriptor)) { + reportError.propertyTypeMismatchOnOverride(memberDescriptor, overridden); + } + else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) { + reportError.returnTypeMismatchOnOverride(memberDescriptor, overridden); + } + + if (checkPropertyKind(overridden, true) && checkPropertyKind(memberDescriptor, false)) { + reportError.varOverriddenByVal(memberDescriptor, overridden); } } } @@ -855,7 +956,7 @@ public class OverrideResolver { private boolean overrideConflict = false; @Override - public void overridingFinalMember(@NotNull CallableMemberDescriptor overridden) { + public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { if (!overrideConflict) { overrideConflict = true; trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataModifier, componentFunction, overridden.getContainingDeclaration())); @@ -863,7 +964,7 @@ public class OverrideResolver { } @Override - public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) { + public void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { if (!overrideConflict) { overrideConflict = true; trace.report(DATA_CLASS_OVERRIDE_CONFLICT.on(dataModifier, componentFunction, overridden.getContainingDeclaration())); @@ -871,22 +972,22 @@ public class OverrideResolver { } @Override - public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) { + public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { throw new IllegalStateException("Component functions are not properties"); } @Override - public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) { + public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { throw new IllegalStateException("Component functions are not properties"); } @Override - public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden) { + public void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor invisibleOverridden) { throw new IllegalStateException("CANNOT_OVERRIDE_INVISIBLE_MEMBER should be reported on the corresponding property"); } @Override - public void nothingToOverride() { + public void nothingToOverride(@NotNull CallableMemberDescriptor overriding) { throw new IllegalStateException("Component functions are OK to override nothing"); } }); diff --git a/compiler/testData/diagnostics/tests/delegation/Delegation_ClashingFunctions.kt b/compiler/testData/diagnostics/tests/delegation/Delegation_ClashingFunctions.kt index 906b40675ab..ccdb6191d74 100644 --- a/compiler/testData/diagnostics/tests/delegation/Delegation_ClashingFunctions.kt +++ b/compiler/testData/diagnostics/tests/delegation/Delegation_ClashingFunctions.kt @@ -10,9 +10,9 @@ interface Three { public fun foo(): String } -class Test123(val v1: One, val v2: Two, val v3: Three) : One by v1, Two by v2, Three by v3 { } -class Test132(val v1: One, val v2: Two, val v3: Three) : One by v1, Three by v3, Two by v2 { } +class Test123(val v1: One, val v2: Two, val v3: Three) : One by v1, Two by v2, Three by v3 { } +class Test132(val v1: One, val v2: Two, val v3: Three) : One by v1, Three by v3, Two by v2 { } class Test312(val v1: One, val v2: Two, val v3: Three) : Three by v3, One by v1, Two by v2 { } class Test321(val v1: One, val v2: Two, val v3: Three) : Three by v3, Two by v2, One by v1 { } -class Test231(val v1: One, val v2: Two, val v3: Three) : Two by v2, Three by v3, One by v1 { } -class Test213(val v1: One, val v2: Two, val v3: Three) : Two by v2, One by v1, Three by v3 { } \ No newline at end of file +class Test231(val v1: One, val v2: Two, val v3: Three) : Two by v2, Three by v3, One by v1 { } +class Test213(val v1: One, val v2: Two, val v3: Three) : Two by v2, One by v1, Three by v3 { } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegation/clashes/returnTypeMismatch.kt b/compiler/testData/diagnostics/tests/delegation/clashes/returnTypeMismatch.kt new file mode 100644 index 00000000000..be2f34ead7e --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/clashes/returnTypeMismatch.kt @@ -0,0 +1,44 @@ +interface IStr { + fun foo(): String +} + +class CStr : IStr { + override fun foo(): String = "" +} + +interface IInt { + fun foo(): Int +} + +class CInt : IInt { + override fun foo(): Int = 42 +} + +interface IGeneric { + fun foo(): T +} + +class CGeneric : IGeneric { + override fun foo(): T { + throw UnsupportedOperationException() + } +} + +abstract class Test1 : IStr by CStr(), IInt + +abstract class Test2 : IStr, IInt by CInt() + +abstract class Test3 : IStr by CStr(), IInt by CInt() + +abstract class Test4 : IStr by CStr(), IGeneric + +abstract class Test5 : IStr by CStr(), IGeneric + +abstract class Test6 : IStr by CStr(), IGeneric + +abstract class Test7 : IGeneric by CGeneric(), IStr + +abstract class Test8 : IGeneric by CGeneric(), IInt + +// Can't test right now due to https://youtrack.jetbrains.com/issue/KT-10258 +// abstract class Test9 : IGeneric by CGeneric(), IGeneric diff --git a/compiler/testData/diagnostics/tests/delegation/clashes/returnTypeMismatch.txt b/compiler/testData/diagnostics/tests/delegation/clashes/returnTypeMismatch.txt new file mode 100644 index 00000000000..5939064ca10 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/clashes/returnTypeMismatch.txt @@ -0,0 +1,110 @@ +package + +public final class CGeneric : IGeneric { + public constructor CGeneric() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): T + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class CInt : IInt { + public constructor CInt() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class CStr : IStr { + public constructor CStr() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IGeneric { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): T + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IInt { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IStr { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Test1 : IStr, IInt { + public constructor Test1() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.String + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Test2 : IStr, IInt { + public constructor Test2() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Test3 : IStr, IInt { + public constructor Test3() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.String + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Test4 : IStr, IGeneric { + public constructor Test4() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.String + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Test5 : IStr, IGeneric { + public constructor Test5() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.String + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Test6 : IStr, IGeneric { + public constructor Test6() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.String + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Test7 : IGeneric, IStr { + public constructor Test7() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.String + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class Test8 : IGeneric, IInt { + public constructor Test8() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.String + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantImplMutableListKotlin.txt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantImplMutableListKotlin.txt index 450e5a6a32d..154d693a1cc 100644 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantImplMutableListKotlin.txt +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/irrelevantImplMutableListKotlin.txt @@ -13,7 +13,7 @@ public open class A : AImpl, kotlin.MutableList { public final override /*2*/ /*fake_override*/ fun contains(/*0*/ element: kotlin.String!): kotlin.Boolean public final override /*2*/ /*fake_override*/ fun containsAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public final override /*2*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.String! + public final override /*2*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.String public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int public final override /*2*/ /*fake_override*/ fun indexOf(/*0*/ element: kotlin.String!): kotlin.Int public final override /*2*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean @@ -25,7 +25,7 @@ public open class A : AImpl, kotlin.MutableList { public final override /*2*/ /*fake_override*/ fun removeAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean public final override /*2*/ /*fake_override*/ fun removeAt(/*0*/ index: kotlin.Int): kotlin.String public final override /*2*/ /*fake_override*/ fun retainAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean - public final override /*2*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: kotlin.String!): kotlin.String! + public final override /*2*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: kotlin.String): kotlin.String public final override /*2*/ /*fake_override*/ fun subList(/*0*/ fromIndex: kotlin.Int, /*1*/ toIndex: kotlin.Int): kotlin.MutableList public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String } @@ -69,7 +69,7 @@ public final class X : A { public final override /*1*/ /*fake_override*/ fun contains(/*0*/ element: kotlin.String!): kotlin.Boolean public final override /*1*/ /*fake_override*/ fun containsAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public final override /*1*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.String! + public final override /*1*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.String public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public final override /*1*/ /*fake_override*/ fun indexOf(/*0*/ element: kotlin.String!): kotlin.Int public final override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean @@ -81,7 +81,7 @@ public final class X : A { public final override /*1*/ /*fake_override*/ fun removeAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean public final override /*1*/ /*fake_override*/ fun removeAt(/*0*/ index: kotlin.Int): kotlin.String public final override /*1*/ /*fake_override*/ fun retainAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean - public final override /*1*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: kotlin.String!): kotlin.String! + public final override /*1*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: kotlin.String): kotlin.String public final override /*1*/ /*fake_override*/ fun subList(/*0*/ fromIndex: kotlin.Int, /*1*/ toIndex: kotlin.Int): kotlin.MutableList public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAt.txt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAt.txt index 6fdc4198820..660bb1265c6 100644 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAt.txt +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAt.txt @@ -53,7 +53,7 @@ public abstract class B : kotlin.MutableList, java.util.AbstractList public open override /*2*/ /*fake_override*/ fun contains(/*0*/ element: T!): kotlin.Boolean public open override /*2*/ /*fake_override*/ fun containsAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public abstract override /*2*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): T! + public abstract override /*2*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): T public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*2*/ /*fake_override*/ fun indexOf(/*0*/ element: T!): kotlin.Int public open override /*2*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean @@ -68,7 +68,7 @@ public abstract class B : kotlin.MutableList, java.util.AbstractList public open override /*2*/ fun removeAt(/*0*/ index: kotlin.Int): T protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun removeRange(/*0*/ p0: kotlin.Int, /*1*/ p1: kotlin.Int): kotlin.Unit public open override /*2*/ /*fake_override*/ fun retainAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean - public open override /*2*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: T!): T! + public open override /*2*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: T): T public open override /*2*/ /*fake_override*/ fun subList(/*0*/ fromIndex: kotlin.Int, /*1*/ toIndex: kotlin.Int): kotlin.MutableList public open override /*1*/ /*fake_override*/ fun toArray(): kotlin.Array<(out) kotlin.Any!>! public open override /*1*/ /*fake_override*/ fun toArray(/*0*/ p0: kotlin.Array<(out) T!>!): kotlin.Array<(out) T!>! diff --git a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.txt b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.txt index f968511bd8d..ae448a51a73 100644 --- a/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.txt +++ b/compiler/testData/diagnostics/tests/j+k/collectionOverrides/removeAtInt.txt @@ -14,7 +14,7 @@ public abstract class A : B { public open override /*1*/ /*fake_override*/ fun contains(/*0*/ element: kotlin.Int!): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun containsAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.Int! + public abstract override /*1*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun indexOf(/*0*/ element: kotlin.Int!): kotlin.Int public open override /*1*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean @@ -29,7 +29,7 @@ public abstract class A : B { public open override /*1*/ fun removeAt(/*0*/ x: kotlin.Int): kotlin.Int protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun removeRange(/*0*/ p0: kotlin.Int, /*1*/ p1: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun retainAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean - public open override /*1*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: kotlin.Int!): kotlin.Int! + public open override /*1*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: kotlin.Int): kotlin.Int public open override /*1*/ /*fake_override*/ fun subList(/*0*/ fromIndex: kotlin.Int, /*1*/ toIndex: kotlin.Int): kotlin.MutableList public open override /*1*/ /*fake_override*/ fun toArray(): kotlin.Array<(out) kotlin.Any!>! public open override /*1*/ /*fake_override*/ fun toArray(/*0*/ p0: kotlin.Array<(out) T!>!): kotlin.Array<(out) T!>! @@ -53,7 +53,7 @@ public abstract class B : kotlin.MutableList, java.util.AbstractList public open override /*2*/ /*fake_override*/ fun contains(/*0*/ element: kotlin.Int!): kotlin.Boolean public open override /*2*/ /*fake_override*/ fun containsAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public abstract override /*2*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.Int! + public abstract override /*2*/ /*fake_override*/ fun get(/*0*/ index: kotlin.Int): kotlin.Int public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*2*/ /*fake_override*/ fun indexOf(/*0*/ element: kotlin.Int!): kotlin.Int public open override /*2*/ /*fake_override*/ fun isEmpty(): kotlin.Boolean @@ -68,7 +68,7 @@ public abstract class B : kotlin.MutableList, java.util.AbstractList public open override /*2*/ fun removeAt(/*0*/ index: kotlin.Int): kotlin.Int protected/*protected and package*/ open override /*1*/ /*fake_override*/ fun removeRange(/*0*/ p0: kotlin.Int, /*1*/ p1: kotlin.Int): kotlin.Unit public open override /*2*/ /*fake_override*/ fun retainAll(/*0*/ elements: kotlin.Collection): kotlin.Boolean - public open override /*2*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: kotlin.Int!): kotlin.Int! + public open override /*2*/ /*fake_override*/ fun set(/*0*/ index: kotlin.Int, /*1*/ element: kotlin.Int): kotlin.Int public open override /*2*/ /*fake_override*/ fun subList(/*0*/ fromIndex: kotlin.Int, /*1*/ toIndex: kotlin.Int): kotlin.MutableList public open override /*1*/ /*fake_override*/ fun toArray(): kotlin.Array<(out) kotlin.Any!>! public open override /*1*/ /*fake_override*/ fun toArray(/*0*/ p0: kotlin.Array<(out) T!>!): kotlin.Array<(out) T!>! diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnType.kt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnType.kt index fba4a9e01d2..1c27c283354 100644 --- a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnType.kt +++ b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnType.kt @@ -21,10 +21,7 @@ interface KDerived2a : K2, J interface KDerived2b : J, K2 interface KDerived12a : K1, K2, J -// public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.String! -interface KDerived12b : K1, J, K2 // TODO -// public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.String? +interface KDerived12b : K1, J, K2 -interface KDerived12c : J, K1, K2 -// public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.String \ No newline at end of file +interface KDerived12c : J, K1, K2 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnType.txt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnType.txt index 89d4705ab07..f960030f435 100644 --- a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnType.txt +++ b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnType.txt @@ -25,14 +25,14 @@ public interface K2 { public interface KDerived12a : K1, K2, J { public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.String! + public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.String public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String } public interface KDerived12b : K1, J, K2 { public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.String? + public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.String public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String } @@ -46,7 +46,7 @@ public interface KDerived12c : J, K1, K2 { public interface KDerived1a : K1, J { public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.String! + public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.String public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeIn.kt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeIn.kt new file mode 100644 index 00000000000..32e735d2c36 --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeIn.kt @@ -0,0 +1,63 @@ +// FILE: InOut.k +interface In +interface Out +interface Inv + +// FILE: J1.java +public interface J1 { + In foo(); +} + +// FILE: J2.java +import org.jetbrains.annotations.*; + +public interface J2 { + @NotNull In foo(); +} + +// FILE: J3.java +import org.jetbrains.annotations.*; + +public interface J3 { + @Nullable In foo(); +} + +// FILE: K.kt +interface K1 { + fun foo(): In +} + +interface K2 { + fun foo(): In +} + +// FIXME TestJ1K1 should have foo(): In, since In <: In. +interface TestJ1K1 : J1, K1 +interface TestK1J1 : K1, J1 + +interface TestJ1K2 : J1, K2 +interface TestK2J1 : K2, J1 + +interface TestJ2K1 : J2, K1 +interface TestK1J2 : K1, J2 + +interface TestJ2K2 : J2, K2 +interface TestK2J2 : K2, J2 + +interface TestJ3K1 : J3, K1 +interface TestK1J3 : K1, J3 + +interface TestJ3K2 : J3, K2 +interface TestK2J3 : K2, J3 + +interface TestJ1K1K2 : J1, K1, K2 +interface TestK1J1K2 : K1, J1, K2 +interface TestK1K2J1 : K1, K2, J1 + +interface TestJ2K1K2 : J2, K1, K2 +interface TestK1J2K2 : K1, J2, K2 +interface TestK1K2J2 : K1, K2, J2 + +interface TestJ3K1K2 : J3, K1, K2 +interface TestK1J3K2 : K1, J3, K2 +interface TestK1K2J3 : K1, K2, J3 \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeIn.txt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeIn.txt new file mode 100644 index 00000000000..fa50898079b --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeIn.txt @@ -0,0 +1,205 @@ +package + +public /*synthesized*/ fun J1(/*0*/ function: () -> In!): J1 +public /*synthesized*/ fun J2(/*0*/ function: () -> In!): J2 +public /*synthesized*/ fun J3(/*0*/ function: () -> In!): J3 + +public interface In { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Inv { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface J1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): In! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface J2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @org.jetbrains.annotations.NotNull() public abstract fun foo(): In + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface J3 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @org.jetbrains.annotations.Nullable() public abstract fun foo(): In? + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface K1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): In + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface K2 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): In + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Out { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestJ1K1 : J1, K1 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestJ1K1K2 : J1, K1, K2 { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): In + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestJ1K2 : J1, K2 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestJ2K1 : J2, K1 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestJ2K1K2 : J2, K1, K2 { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): In + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestJ2K2 : J2, K2 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestJ3K1 : J3, K1 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestJ3K1K2 : J3, K1, K2 { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): In + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestJ3K2 : J3, K2 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK1J1 : K1, J1 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK1J1K2 : K1, J1, K2 { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): In + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK1J2 : K1, J2 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @org.jetbrains.annotations.NotNull() public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK1J2K2 : K1, J2, K2 { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): In + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK1J3 : K1, J3 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK1J3K2 : K1, J3, K2 { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): In + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK1K2J1 : K1, K2, J1 { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): In + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK1K2J2 : K1, K2, J2 { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @org.jetbrains.annotations.NotNull() public abstract override /*3*/ /*fake_override*/ fun foo(): In + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK1K2J3 : K1, K2, J3 { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): In + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK2J1 : K2, J1 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK2J2 : K2, J2 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + @org.jetbrains.annotations.NotNull() public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface TestK2J3 : K2, J3 { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): In + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeList.kt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeList.kt new file mode 100644 index 00000000000..dc217781eaa --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeList.kt @@ -0,0 +1,37 @@ +// FILE: J.java +public interface J { + java.util.List foo(); +} + +// FILE: K.kt +interface ILNS { + fun foo(): List +} + +interface IMLS { + fun foo(): MutableList +} + +interface IMLNS { + fun foo(): MutableList +} + +interface ILS { + fun foo(): List +} + +interface Test1 : ILNS, J +interface Test2 : J, ILNS + +interface Test3 : IMLS, J +interface Test4 : J, IMLS + +interface Test5 : ILNS, IMLS, J +interface Test6 : ILNS, J, IMLS +interface Test7 : J, ILNS, IMLS + +// ILS and IMLNS are incompatible + +interface Test8 : J, IMLNS, ILS +interface Test9 : IMLNS, J, ILS +interface Test10 : IMLNS, ILS, J \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeList.txt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeList.txt new file mode 100644 index 00000000000..e035ef8128f --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeList.txt @@ -0,0 +1,108 @@ +package + +public /*synthesized*/ fun J(/*0*/ function: () -> kotlin.(Mutable)List!): J + +public interface ILNS { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.List + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface ILS { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.List + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IMLNS { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.MutableList + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IMLS { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.MutableList + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface J { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.(Mutable)List! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test1 : ILNS, J { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.List + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test10 : IMLNS, ILS, J { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.MutableList + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test2 : J, ILNS { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.List + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test3 : IMLS, J { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.MutableList + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test4 : J, IMLS { + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*2*/ /*fake_override*/ fun foo(): kotlin.MutableList + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test5 : ILNS, IMLS, J { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.MutableList + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test6 : ILNS, J, IMLS { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.MutableList + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test7 : J, ILNS, IMLS { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.MutableList + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test8 : J, IMLNS, ILS { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.MutableList + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Test9 : IMLNS, J, ILS { + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*3*/ /*fake_override*/ fun foo(): kotlin.MutableList + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/propertyTypeMismatch.kt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/valTypeMismatch.kt similarity index 100% rename from compiler/testData/diagnostics/tests/override/clashesOnInheritance/propertyTypeMismatch.kt rename to compiler/testData/diagnostics/tests/override/clashesOnInheritance/valTypeMismatch.kt diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/propertyTypeMismatch.txt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/valTypeMismatch.txt similarity index 100% rename from compiler/testData/diagnostics/tests/override/clashesOnInheritance/propertyTypeMismatch.txt rename to compiler/testData/diagnostics/tests/override/clashesOnInheritance/valTypeMismatch.txt diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/varTypeMismatch.kt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/varTypeMismatch.kt new file mode 100644 index 00000000000..68ac74ecb34 --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/varTypeMismatch.kt @@ -0,0 +1,29 @@ +open class A { + open var foo: Boolean = true +} + +interface IA { + var foo: String +} + +interface IAA { + var foo: Int +} + +interface IGA { + var foo: T +} + +class B1: A(), IA + +class B2: A(), IA, IAA + +abstract class B3: IA, IAA + +class BS1: A(), IGA + +class BS2: A(), IGA + +class BS3: A(), IGA + +class BG1: A(), IGA diff --git a/compiler/testData/diagnostics/tests/override/clashesOnInheritance/varTypeMismatch.txt b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/varTypeMismatch.txt new file mode 100644 index 00000000000..a8ca3c0a73a --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/clashesOnInheritance/varTypeMismatch.txt @@ -0,0 +1,86 @@ +package + +public open class A { + public constructor A() + public open var foo: kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class B1 : A, IA { + public constructor B1() + public open override /*2*/ /*fake_override*/ var foo: kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class B2 : A, IA, IAA { + public constructor B2() + public open override /*3*/ /*fake_override*/ var foo: kotlin.Boolean + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public abstract class B3 : IA, IAA { + public constructor B3() + public abstract override /*2*/ /*fake_override*/ var foo: kotlin.String + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class BG1 : A, IGA { + public constructor BG1() + public open override /*2*/ /*fake_override*/ var foo: kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class BS1 : A, IGA { + public constructor BS1() + public open override /*2*/ /*fake_override*/ var foo: kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class BS2 : A, IGA { + public constructor BS2() + public open override /*2*/ /*fake_override*/ var foo: kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class BS3 : A, IGA { + public constructor BS3() + public open override /*2*/ /*fake_override*/ var foo: kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IA { + public abstract var foo: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IAA { + public abstract var foo: kotlin.Int + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IGA { + public abstract var foo: T + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.kt b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.kt index bbebad6f852..c57cb72afa5 100644 --- a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.kt +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.kt @@ -24,7 +24,7 @@ fun foo(k: KotlinClass) { k.setSomething4("") k.something4 += "" k.setSomething4(null) - k.something4 = null + k.something4 = null useString(k.getSomething5()) useString(k.something5) diff --git a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.txt b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.txt index 8b1fe9a42e2..2c2ea5d4265 100644 --- a/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.txt +++ b/compiler/testData/diagnostics/tests/syntheticExtensions/javaProperties/KotlinOverridesJava.txt @@ -30,7 +30,7 @@ public abstract class KotlinClass : JavaClass, KotlinInterface, JavaInterface { public open override /*2*/ fun getSomething1(): kotlin.Int public open override /*1*/ /*fake_override*/ fun getSomething2(): kotlin.Int public open override /*1*/ fun getSomething3(): kotlin.String - public abstract override /*2*/ /*fake_override*/ fun getSomething4(): kotlin.String! + public abstract override /*2*/ /*fake_override*/ fun getSomething4(): kotlin.String public open override /*1*/ fun getSomething5(): kotlin.String public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ fun setSomething4(/*0*/ value: kotlin.String): kotlin.Unit diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overrides.txt b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overrides.txt index acd85cafb7d..51401cf6ad7 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overrides.txt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/overrides.txt @@ -26,7 +26,7 @@ public interface B : A { public interface C : A, A1 { public abstract override /*1*/ /*fake_override*/ fun dynamic(/*0*/ p: dynamic): dynamic public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public abstract override /*2*/ /*fake_override*/ fun foo(/*0*/ p: dynamic): dynamic + public abstract override /*2*/ /*fake_override*/ fun foo(/*0*/ p: P): R public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 57ecf2029de..812e028b794 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -4754,6 +4754,21 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegation/Delegation_ScopeInitializationOrder.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/diagnostics/tests/delegation/clashes") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Clashes extends AbstractDiagnosticsTest { + public void testAllFilesPresentInClashes() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/delegation/clashes"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("returnTypeMismatch.kt") + public void testReturnTypeMismatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegation/clashes/returnTypeMismatch.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/diagnostics/tests/deparenthesize") @@ -11315,9 +11330,15 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } - @TestMetadata("propertyTypeMismatch.kt") - public void testPropertyTypeMismatch() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/clashesOnInheritance/propertyTypeMismatch.kt"); + @TestMetadata("flexibleReturnTypeIn.kt") + public void testFlexibleReturnTypeIn() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeIn.kt"); + doTest(fileName); + } + + @TestMetadata("flexibleReturnTypeList.kt") + public void testFlexibleReturnTypeList() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/clashesOnInheritance/flexibleReturnTypeList.kt"); doTest(fileName); } @@ -11332,6 +11353,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/clashesOnInheritance/unrelatedInherited.kt"); doTest(fileName); } + + @TestMetadata("valTypeMismatch.kt") + public void testValTypeMismatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/clashesOnInheritance/valTypeMismatch.kt"); + doTest(fileName); + } + + @TestMetadata("varTypeMismatch.kt") + public void testVarTypeMismatch() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/clashesOnInheritance/varTypeMismatch.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/tests/override/parameterNames") diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index cbbd90d7b14..e613712bb99 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.types.KotlinType; +import org.jetbrains.kotlin.types.TypeCapabilitiesKt; import org.jetbrains.kotlin.types.TypeConstructor; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; @@ -320,14 +321,16 @@ public class OverridingUtil { } public static boolean isMoreSpecific(@NotNull CallableMemberDescriptor a, @NotNull CallableMemberDescriptor b) { + KotlinType aReturnType = a.getReturnType(); + assert aReturnType != null : "Return type is null for " + a; + // Use upper bound for flexible type. + aReturnType = TypeCapabilitiesKt.getSupertypeRepresentative(aReturnType); + KotlinType bReturnType = b.getReturnType(); + assert bReturnType != null : "Return type is null for " + b; + if (a instanceof SimpleFunctionDescriptor) { assert b instanceof SimpleFunctionDescriptor : "b is " + b.getClass(); - KotlinType aReturnType = a.getReturnType(); - assert aReturnType != null; - KotlinType bReturnType = b.getReturnType(); - assert bReturnType != null; - return KotlinTypeChecker.DEFAULT.isSubtypeOf(aReturnType, bReturnType); } if (a instanceof PropertyDescriptor) { @@ -336,11 +339,16 @@ public class OverridingUtil { PropertyDescriptor pa = (PropertyDescriptor) a; PropertyDescriptor pb = (PropertyDescriptor) b; if (pa.isVar() && pb.isVar()) { - return KotlinTypeChecker.DEFAULT.equalTypes(pa.getType(), pb.getType()); + return KotlinTypeChecker.DEFAULT.equalTypes(aReturnType, bReturnType); + } + else if (!pa.isVar() && pb.isVar()) { + // val can't be more specific than var, regardless of return type. + return false; + } + else { + // both vals or var effectiveOverridden = allInvisible ? overridables : visibleOverridables; + // FIXME doesn't work as expected for flexible types: should create a refined signature. + // Current algorithm produces bad results in presence of annotated Java signatures such as: + // J: foo(s: String!): String -- @NotNull String foo(String s); + // K: foo(s: String): String? + // --> 'foo(s: String!): String' as an inherited signature with most specific return type. + // This is bad because it can be overridden by 'foo(s: String?): String', which is not override-equivalent with K::foo above. + // Should be 'foo(s: String): String'. Modality modality = getMinimalModality(effectiveOverridden); Visibility visibility = allInvisible ? Visibilities.INVISIBLE_FAKE : Visibilities.INHERITED; CallableMemberDescriptor mostSpecific = selectMostSpecificMemberFromSuper(effectiveOverridden);