Discriminate overloading expect MemberDescriptors
Issue #KT-38298
This commit is contained in:
@@ -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
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,8 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
||||
it == overriddenDescriptor || OverridingUtil.overrides(
|
||||
it,
|
||||
overriddenDescriptor,
|
||||
it.module.isTypeRefinementEnabled()
|
||||
it.module.isTypeRefinementEnabled(),
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -135,8 +135,8 @@ open class OverloadingConflictResolver<C : Any>(
|
||||
if (DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent(
|
||||
me,
|
||||
other,
|
||||
isTypeRefinementEnabled,
|
||||
ignoreReturnType
|
||||
allowCopiesFromTheSameDeclaration = isTypeRefinementEnabled,
|
||||
ignoreReturnType = ignoreReturnType
|
||||
)
|
||||
) {
|
||||
continue@outerLoop
|
||||
|
||||
@@ -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 = "";
|
||||
|
||||
+17
-10
@@ -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
|
||||
|
||||
@@ -126,10 +126,10 @@ public class OverridingUtil {
|
||||
Pair<CallableDescriptor, CallableDescriptor> 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 <D extends CallableDescriptor> 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;
|
||||
}
|
||||
|
||||
@@ -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 -> {
|
||||
|
||||
Reference in New Issue
Block a user