Discriminate overloading expect MemberDescriptors

Issue #KT-38298
This commit is contained in:
Dmitriy Dolovov
2020-04-17 15:27:23 +07:00
parent 34ae35b2aa
commit 90e888a1b6
7 changed files with 56 additions and 23 deletions
@@ -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
)
}
}
@@ -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 = "";
@@ -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 -> {