ActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker: reuse "expect-actual" matcher

In scope of: KT-22841
Review: https://jetbrains.team/p/kt/reviews/11867/timeline

Reduce complexity by reusing "expect-actual matcher" (namely
`AbstractExpectActualCompatibilityChecker.getCallablesCompatibility`)

The current solution has worse algorithmic complexity. Previously it was
O(n) in the best case, where `n` is a number of members. Now, it's
O(m^2), where `m` is number of members in one overload group. But we
prefer to have worse complexity but reuse expect-actual matcher, number
of elements in one overload group shall not be big on real world
examples.

The previous logic was non-trivial because it compared types with with
double comparison in `equals`.
This commit is contained in:
Nikita Bobko
2023-08-24 12:35:56 +02:00
committed by teamcity
parent 17089276a7
commit 3722f4d7d6
13 changed files with 123 additions and 228 deletions
@@ -1,16 +0,0 @@
// MODULE: m1-common
// FILE: common.kt
expect open class Foo {
fun foo()
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual open class Foo {
// Hypothetically, it's more restricting than necessary. I can't see how actualizing final -> open can breaking anything.
// But technically, actual and expect scopes don't match
actual open fun foo() {
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
@@ -8,9 +9,8 @@ expect open class Foo {
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual open <!ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_MEMBERS_AS_NON_FINAL_EXPECT_CLASSIFIER!>class Foo<!> {
// Hypothetically, it's more restricting than necessary. I can't see how actualizing final -> open can breaking anything.
// But technically, actual and expect scopes don't match
actual <!MODALITY_CHANGED_IN_NON_FINAL_EXPECT_CLASSIFIER_ACTUALIZATION!>open<!> fun foo() {
actual open class Foo {
// final -> open is a legal modality change
actual open fun foo() {
}
}
@@ -12,6 +12,8 @@ expect open class Foo {
actual open class Foo {
actual fun foo() {}
// Expected: NON_ACTUAL_MEMBER_DECLARED_IN_EXPECT_NON_FINAL_CLASSIFIER_ACTUALIZATION.
// But it doesn't work because context receivers are not yet supported in expect actual matcher KT-61447
context(Int)
fun foo() {} // accidential override can happen with this injected fun. That's why it's prohibited
fun foo() {}
}
@@ -9,9 +9,11 @@ expect open class Foo {
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual open <!ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_MEMBERS_AS_NON_FINAL_EXPECT_CLASSIFIER!>class Foo<!> {
actual open class Foo {
actual fun foo() {}
// Expected: NON_ACTUAL_MEMBER_DECLARED_IN_EXPECT_NON_FINAL_CLASSIFIER_ACTUALIZATION.
// But it doesn't work because context receivers are not yet supported in expect actual matcher KT-61447
context(Int)
fun <!ACTUAL_MISSING, NON_ACTUAL_MEMBER_DECLARED_IN_EXPECT_NON_FINAL_CLASSIFIER_ACTUALIZATION!>foo<!>() {} // accidential override can happen with this injected fun. That's why it's prohibited
fun <!ACTUAL_MISSING!>foo<!>() {}
}
@@ -0,0 +1,21 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// MODULE: m1-common
// FILE: common.kt
<!INCOMPATIBLE_MATCHING{JVM}!>expect open class Container {
<!INCOMPATIBLE_MATCHING{JVM}!>internal open fun internalFun()<!>
}<!>
// MODULE: m2-jvm()()(m1-common)
// FILE: foo/Foo.java
package foo;
public class Foo {
public void internalFun() {}
}
// FILE: jvm.kt
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Container<!> = foo.Foo
@@ -3,7 +3,7 @@
// FILE: common.kt
expect open class Container {
internal fun internalFun()
internal open fun internalFun()
}
// MODULE: m2-jvm()()(m1-common)
@@ -13,9 +13,9 @@ expect open class Container {
package foo;
public class Foo {
public final void internalFun() {}
public void internalFun() {}
}
// FILE: jvm.kt
actual typealias <!ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_MEMBERS_AS_NON_FINAL_EXPECT_CLASSIFIER!>Container<!> = foo.Foo
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Container<!> = foo.Foo