diff --git a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt index 02bf61f344e..024ab849243 100644 --- a/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt +++ b/compiler/backend-common/src/org/jetbrains/kotlin/backend/common/bridges/impl.kt @@ -125,11 +125,16 @@ fun findImplementationFromInterface(descriptor: CallableMemberDescriptor): Calla * The returned function should be called from TImpl-bridges generated for the given fake override. */ fun firstSuperMethodFromKotlin( - descriptor: CallableMemberDescriptor, - implementation: CallableMemberDescriptor + descriptor: CallableMemberDescriptor, + implementation: CallableMemberDescriptor ): CallableMemberDescriptor? { return descriptor.overriddenDescriptors.firstOrNull { overridden -> overridden.modality != Modality.ABSTRACT && - (overridden == implementation || OverridingUtil.overrides(overridden, implementation, overridden.module.isTypeRefinementEnabled())) + (overridden == implementation || OverridingUtil.overrides( + overridden, + implementation, + overridden.module.isTypeRefinementEnabled(), + true + )) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt index 59e14cc48a8..62952b4a7cc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt @@ -178,7 +178,8 @@ class DelegationResolver private constructor( it == overriddenDescriptor || OverridingUtil.overrides( it, overriddenDescriptor, - it.module.isTypeRefinementEnabled() + it.module.isTypeRefinementEnabled(), + true ) } } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt index 946ba11042b..3958762e7e3 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/results/OverloadingConflictResolver.kt @@ -135,8 +135,8 @@ open class OverloadingConflictResolver( if (DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent( me, other, - isTypeRefinementEnabled, - ignoreReturnType + allowCopiesFromTheSameDeclaration = isTypeRefinementEnabled, + ignoreReturnType = ignoreReturnType ) ) { continue@outerLoop diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java index 360429ed747..02395c79d82 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/ExpectedResolveData.java @@ -329,7 +329,7 @@ public abstract class ExpectedResolveData { } private static void assertDescriptorsEqual(String message, DeclarationDescriptor expected, DeclarationDescriptor actual) { - if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(expected, actual, true)) { + if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(expected, actual, true, true)) { return; } String formatted = ""; diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorEquivalenceForOverrides.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorEquivalenceForOverrides.kt index 7e9080649e5..c62f580eb91 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorEquivalenceForOverrides.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorEquivalenceForOverrides.kt @@ -24,20 +24,26 @@ object DescriptorEquivalenceForOverrides { fun areEquivalent( a: DeclarationDescriptor?, b: DeclarationDescriptor?, - allowCopiesFromTheSameDeclaration: Boolean + allowCopiesFromTheSameDeclaration: Boolean, + distinguishExpectsAndNonExpects: Boolean = true ): Boolean { return when { - a is ClassDescriptor && - b is ClassDescriptor -> areClassesEquivalent(a, b) + a is ClassDescriptor && b is ClassDescriptor -> areClassesEquivalent(a, b) - a is TypeParameterDescriptor && - b is TypeParameterDescriptor -> areTypeParametersEquivalent(a, b, allowCopiesFromTheSameDeclaration) + a is TypeParameterDescriptor && b is TypeParameterDescriptor -> areTypeParametersEquivalent( + a, + b, + allowCopiesFromTheSameDeclaration + ) - a is CallableDescriptor && - b is CallableDescriptor -> areCallableDescriptorsEquivalent(a, b, allowCopiesFromTheSameDeclaration) + a is CallableDescriptor && b is CallableDescriptor -> areCallableDescriptorsEquivalent( + a, + b, + allowCopiesFromTheSameDeclaration = allowCopiesFromTheSameDeclaration, + distinguishExpectsAndNonExpects = distinguishExpectsAndNonExpects + ) - a is PackageFragmentDescriptor && - b is PackageFragmentDescriptor -> (a).fqName == (b).fqName + a is PackageFragmentDescriptor && b is PackageFragmentDescriptor -> (a).fqName == (b).fqName else -> a == b } @@ -72,14 +78,15 @@ object DescriptorEquivalenceForOverrides { a: CallableDescriptor, b: CallableDescriptor, allowCopiesFromTheSameDeclaration: Boolean, + distinguishExpectsAndNonExpects: Boolean = true, ignoreReturnType: Boolean = false ): Boolean { if (a == b) return true if (a.name != b.name) return false + if (distinguishExpectsAndNonExpects && a is MemberDescriptor && b is MemberDescriptor && a.isExpect != b.isExpect) return false if (a.containingDeclaration == b.containingDeclaration) { if (!allowCopiesFromTheSameDeclaration) return false if (a.singleSource() != b.singleSource()) return false - if (a is MemberDescriptor && b is MemberDescriptor && a.isExpect != b.isExpect) return false } // Distinct locals are not equivalent diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index 7a7f797cd69..e7c5a025715 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -126,10 +126,10 @@ public class OverridingUtil { Pair meAndOther = transformFirst.invoke(meD, otherD); CallableDescriptor me = meAndOther.component1(); CallableDescriptor other = meAndOther.component2(); - if (overrides(me, other, allowDescriptorCopies)) { + if (overrides(me, other, allowDescriptorCopies, true)) { iterator.remove(); } - else if (overrides(other, me, allowDescriptorCopies)) { + else if (overrides(other, me, allowDescriptorCopies, true)) { continue outerLoop; } } @@ -145,7 +145,10 @@ public class OverridingUtil { * @return whether f overrides g */ public static boolean overrides( - @NotNull D f, @NotNull D g, boolean allowDeclarationCopies + @NotNull D f, + @NotNull D g, + boolean allowDeclarationCopies, + boolean distinguishExpectsAndNonExpects ) { // In a multi-module project different "copies" of the same class may be present in different libraries, // that's why we use structural equivalence for members (DescriptorEquivalenceForOverrides). @@ -155,11 +158,27 @@ public class OverridingUtil { // we'll be getting sets of members that do not override each other, but are structurally equivalent. // As other code relies on no equal descriptors passed here, we guard against f == g, but this may not be necessary // Note that this is needed for the usage of this function in the IDE code - if (!f.equals(g) && DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(f.getOriginal(), g.getOriginal(), allowDeclarationCopies)) return true; + if (!f.equals(g) + && DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent( + f.getOriginal(), + g.getOriginal(), + allowDeclarationCopies, + distinguishExpectsAndNonExpects + ) + ) { + return true; + } CallableDescriptor originalG = g.getOriginal(); for (D overriddenFunction : DescriptorUtils.getAllOverriddenDescriptors(f)) { - if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent(originalG, overriddenFunction, allowDeclarationCopies)) return true; + if (DescriptorEquivalenceForOverrides.INSTANCE.areEquivalent( + originalG, + overriddenFunction, + allowDeclarationCopies, + distinguishExpectsAndNonExpects + )) { + return true; + } } return false; } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/utils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/utils.kt index a275a98f856..f2fa5f9a692 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/utils.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/usagesSearch/utils.kt @@ -267,7 +267,8 @@ fun PsiReference.isCallableOverrideUsage(declaration: KtNamedDeclaration): Boole usageDescriptor != null && OverridingUtil.overrides( usageDescriptor, targetDescriptor, - usageDescriptor.module.isTypeRefinementEnabled() + usageDescriptor.module.isTypeRefinementEnabled(), + false // don't distinguish between expect and non-expect callable descriptors, KT-38298, KT-38589 ) } is PsiMethod -> {