[FE] Convert specific diagnostic for actual function with default arguments into a common incompatibility

^KT-59665 Fixed
Review: https://jetbrains.team/p/kt/reviews/11039/timeline

It's better to have this logic in common place
(AbstractExpectActualCompatibilityChecker) to avoid missing compilation
errors in the future

This commit fixes:
1. Missing compilation error for actual function with default arguments
   for 'actual typealias' KT-59665
2. Missing compilation error for actual function with default arguments
   for actual fake-override KT-59665

Alternative solution for KT-59665 is to create a special checker.

"incompatibility" vs "special checker":

Arguments for common incompatibility:
- What if we had a rule that expect and actual default params must
  match? If so then it certainly would be an incompatibility.
- Technically, we do the matching of expect and actual params (because
  we allow default params in common ancestors of expect and actual
  declarations).
- It's hard to check that the actual definition doesn't use default
  params because `ExpectedActualResolver.findActualForExpected` filters
  out fake-overrides and doesn't return them. It's not clear logic for
  me, that I'm afraid to touch.
  implicitActualFakeOverride_AbstractMap.kt test breaks if you drop this
  weird logic
- WEAK incompatibilities can be considered as "checkers". So it doesn't
  matter how it's implemented, as a "incompatibility" or a "checker"

Arguments against common incompatibility:
- Although we match expect and actual declarations to allow default
  params in common ancestors of expect and actual declarations, it's
  still can be considered that we check that the actual declaration
  doesn't have default params. And it doesn't feel right that we check
  correctness of the actual declaration in expect-actual matcher.
- ~~It may change the rules of expect actual matching~~ (It's not true,
  because ActualFunctionWithDefaultParameters is declared as WEAK
  incompatibility)
This commit is contained in:
Nikita Bobko
2023-06-28 16:42:26 +02:00
committed by teamcity
parent ab8913dee8
commit d39755b578
41 changed files with 450 additions and 59 deletions
@@ -0,0 +1,16 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
expect class A {
fun foo(a: Int): Int
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
interface FooProvider {
fun foo(a: Int = 2): Int = 42
}
actual class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>A<!> : FooProvider
@@ -0,0 +1,12 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
interface Shared {
fun sharedMethod(withDefaultParam: Int = 2) {}
}
expect class Foo : Shared
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Shared
@@ -0,0 +1,14 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
interface Shared {
fun sharedMethod(withDefaultParam: Int = 2) {}
}
interface Transitive
expect class Foo : Transitive
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Transitive
@@ -0,0 +1,20 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
expect class Foo {
fun foo(param: Int)
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> : A
interface A : B<Int> {
override fun getDefault(): Int = 3
}
interface B<T> {
fun foo(param: T = getDefault()) {}
fun getDefault(): T
}
@@ -0,0 +1,18 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
expect class Foo {
fun foo(param: Int)
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : A
interface A : B {
override fun foo(param: Int) {}
}
interface B {
fun foo(param: Int) {}
}
@@ -0,0 +1,18 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
expect class Foo {
fun foo(param: Int)
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> : A
interface A : B {
override fun foo(param: Int) {}
}
interface B {
fun foo(param: Int = 3) {}
}
@@ -0,0 +1,15 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
expect class Foo {
fun foo(a: Int)
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> = FooImpl
class FooImpl {
fun foo(a: Int = 2) {
}
}
@@ -0,0 +1,13 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
public expect fun <T : Comparable<T>> Array<out T>.sort(fromIndex: Int = 0, toIndex: Int = size): Unit
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
public actual fun <T : Comparable<T>> Array<out T>.sort(<!ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS!>fromIndex: Int = 0<!>, <!ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS!>toIndex: Int = size<!>): Unit {
}
public fun <T> Array<out T>.sort(fromIndex: Int = 0, toIndex: Int = size): Unit {
}
@@ -0,0 +1,13 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
public expect fun <T : Comparable<T>> Array<out T>.sort(fromIndex: Int = 0, toIndex: Int = size): Unit
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
public actual fun <T : Comparable<T>> Array<out T>.sort(fromIndex: Int, toIndex: Int): Unit {
}
public fun <T> Array<out T>.sort(fromIndex: Int = 0, toIndex: Int = size): Unit {
}
@@ -7,4 +7,4 @@ expect class DefaultArgsInConstructor(p1: String = "common", p2: String = "commo
// FILE: jvm.kt
class DefaultArgsInConstructorImpl(p1: String = "common", p2: String = "common", p3: String)
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias DefaultArgsInConstructor = DefaultArgsInConstructorImpl<!>
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>DefaultArgsInConstructor<!> = DefaultArgsInConstructorImpl<!>
@@ -28,13 +28,13 @@ class AImpl {
fun foo(p1: String = "impl", p2: String = "impl", p3: String) {}
}
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias A = AImpl<!>
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>A<!> = AImpl<!>
class BImpl {
fun foo(s: String = "impl") {}
}
actual typealias B = BImpl
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>B<!> = BImpl
class WithDefaultArgFromSuperImpl : I {
override fun methodWithDefaultArg(s: String) {}
@@ -28,13 +28,13 @@ class AImpl {
fun foo(p1: String = "impl", p2: String = "impl", p3: String) {}
}
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias A = AImpl<!>
<!DEFAULT_ARGUMENTS_IN_EXPECT_WITH_ACTUAL_TYPEALIAS!>actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>A<!> = AImpl<!>
class BImpl {
fun foo(s: String = "impl") {}
}
actual typealias B = BImpl
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>B<!> = BImpl
class WithDefaultArgFromSuperImpl : I {
override fun methodWithDefaultArg(s: String) {}