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.
|
* The returned function should be called from TImpl-bridges generated for the given fake override.
|
||||||
*/
|
*/
|
||||||
fun firstSuperMethodFromKotlin(
|
fun firstSuperMethodFromKotlin(
|
||||||
descriptor: CallableMemberDescriptor,
|
descriptor: CallableMemberDescriptor,
|
||||||
implementation: CallableMemberDescriptor
|
implementation: CallableMemberDescriptor
|
||||||
): CallableMemberDescriptor? {
|
): CallableMemberDescriptor? {
|
||||||
return descriptor.overriddenDescriptors.firstOrNull { overridden ->
|
return descriptor.overriddenDescriptors.firstOrNull { overridden ->
|
||||||
overridden.modality != Modality.ABSTRACT &&
|
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 || OverridingUtil.overrides(
|
||||||
it,
|
it,
|
||||||
overriddenDescriptor,
|
overriddenDescriptor,
|
||||||
it.module.isTypeRefinementEnabled()
|
it.module.isTypeRefinementEnabled(),
|
||||||
|
true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -135,8 +135,8 @@ open class OverloadingConflictResolver<C : Any>(
|
|||||||
if (DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent(
|
if (DescriptorEquivalenceForOverrides.areCallableDescriptorsEquivalent(
|
||||||
me,
|
me,
|
||||||
other,
|
other,
|
||||||
isTypeRefinementEnabled,
|
allowCopiesFromTheSameDeclaration = isTypeRefinementEnabled,
|
||||||
ignoreReturnType
|
ignoreReturnType = ignoreReturnType
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
continue@outerLoop
|
continue@outerLoop
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ public abstract class ExpectedResolveData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void assertDescriptorsEqual(String message, DeclarationDescriptor expected, DeclarationDescriptor actual) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
String formatted = "";
|
String formatted = "";
|
||||||
|
|||||||
+17
-10
@@ -24,20 +24,26 @@ object DescriptorEquivalenceForOverrides {
|
|||||||
fun areEquivalent(
|
fun areEquivalent(
|
||||||
a: DeclarationDescriptor?,
|
a: DeclarationDescriptor?,
|
||||||
b: DeclarationDescriptor?,
|
b: DeclarationDescriptor?,
|
||||||
allowCopiesFromTheSameDeclaration: Boolean
|
allowCopiesFromTheSameDeclaration: Boolean,
|
||||||
|
distinguishExpectsAndNonExpects: Boolean = true
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return when {
|
return when {
|
||||||
a is ClassDescriptor &&
|
a is ClassDescriptor && b is ClassDescriptor -> areClassesEquivalent(a, b)
|
||||||
b is ClassDescriptor -> areClassesEquivalent(a, b)
|
|
||||||
|
|
||||||
a is TypeParameterDescriptor &&
|
a is TypeParameterDescriptor && b is TypeParameterDescriptor -> areTypeParametersEquivalent(
|
||||||
b is TypeParameterDescriptor -> areTypeParametersEquivalent(a, b, allowCopiesFromTheSameDeclaration)
|
a,
|
||||||
|
b,
|
||||||
|
allowCopiesFromTheSameDeclaration
|
||||||
|
)
|
||||||
|
|
||||||
a is CallableDescriptor &&
|
a is CallableDescriptor && b is CallableDescriptor -> areCallableDescriptorsEquivalent(
|
||||||
b is CallableDescriptor -> areCallableDescriptorsEquivalent(a, b, allowCopiesFromTheSameDeclaration)
|
a,
|
||||||
|
b,
|
||||||
|
allowCopiesFromTheSameDeclaration = allowCopiesFromTheSameDeclaration,
|
||||||
|
distinguishExpectsAndNonExpects = distinguishExpectsAndNonExpects
|
||||||
|
)
|
||||||
|
|
||||||
a is PackageFragmentDescriptor &&
|
a is PackageFragmentDescriptor && b is PackageFragmentDescriptor -> (a).fqName == (b).fqName
|
||||||
b is PackageFragmentDescriptor -> (a).fqName == (b).fqName
|
|
||||||
|
|
||||||
else -> a == b
|
else -> a == b
|
||||||
}
|
}
|
||||||
@@ -72,14 +78,15 @@ object DescriptorEquivalenceForOverrides {
|
|||||||
a: CallableDescriptor,
|
a: CallableDescriptor,
|
||||||
b: CallableDescriptor,
|
b: CallableDescriptor,
|
||||||
allowCopiesFromTheSameDeclaration: Boolean,
|
allowCopiesFromTheSameDeclaration: Boolean,
|
||||||
|
distinguishExpectsAndNonExpects: Boolean = true,
|
||||||
ignoreReturnType: Boolean = false
|
ignoreReturnType: Boolean = false
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (a == b) return true
|
if (a == b) return true
|
||||||
if (a.name != b.name) return false
|
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 (a.containingDeclaration == b.containingDeclaration) {
|
||||||
if (!allowCopiesFromTheSameDeclaration) return false
|
if (!allowCopiesFromTheSameDeclaration) return false
|
||||||
if (a.singleSource() != b.singleSource()) 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
|
// Distinct locals are not equivalent
|
||||||
|
|||||||
@@ -126,10 +126,10 @@ public class OverridingUtil {
|
|||||||
Pair<CallableDescriptor, CallableDescriptor> meAndOther = transformFirst.invoke(meD, otherD);
|
Pair<CallableDescriptor, CallableDescriptor> meAndOther = transformFirst.invoke(meD, otherD);
|
||||||
CallableDescriptor me = meAndOther.component1();
|
CallableDescriptor me = meAndOther.component1();
|
||||||
CallableDescriptor other = meAndOther.component2();
|
CallableDescriptor other = meAndOther.component2();
|
||||||
if (overrides(me, other, allowDescriptorCopies)) {
|
if (overrides(me, other, allowDescriptorCopies, true)) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
else if (overrides(other, me, allowDescriptorCopies)) {
|
else if (overrides(other, me, allowDescriptorCopies, true)) {
|
||||||
continue outerLoop;
|
continue outerLoop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +145,10 @@ public class OverridingUtil {
|
|||||||
* @return whether f overrides g
|
* @return whether f overrides g
|
||||||
*/
|
*/
|
||||||
public static <D extends CallableDescriptor> boolean overrides(
|
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,
|
// 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).
|
// 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.
|
// 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
|
// 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
|
// 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();
|
CallableDescriptor originalG = g.getOriginal();
|
||||||
for (D overriddenFunction : DescriptorUtils.getAllOverriddenDescriptors(f)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -267,7 +267,8 @@ fun PsiReference.isCallableOverrideUsage(declaration: KtNamedDeclaration): Boole
|
|||||||
usageDescriptor != null && OverridingUtil.overrides(
|
usageDescriptor != null && OverridingUtil.overrides(
|
||||||
usageDescriptor,
|
usageDescriptor,
|
||||||
targetDescriptor,
|
targetDescriptor,
|
||||||
usageDescriptor.module.isTypeRefinementEnabled()
|
usageDescriptor.module.isTypeRefinementEnabled(),
|
||||||
|
false // don't distinguish between expect and non-expect callable descriptors, KT-38298, KT-38589
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is PsiMethod -> {
|
is PsiMethod -> {
|
||||||
|
|||||||
Reference in New Issue
Block a user