[FIR, IR] Prohibit actualization of expect Kotlin property to Java field
The problem from KT-63624 was that during matching phase we must choose only one candidate, but in Java we can have two successfully matched properties: 1) from field and 2) from method, which overrides Kotlin property. See test `propertyAgainstJavaPrivateFieldAndPublicMethod.kt`. As a result, we choose field candidate, throw away method candidate, and then fail during visibility check. Instead of inventing special rule of prioritizing field over method it was decided to prohibit actualization to Java field at all because: 1. It doesn't seem that Java fields actualization was implemented in K1 on purpose 2. People usually don't use public Java fields, and use instead private field + getter, especially when compatibility is important, so it shouldn't be a breaking change Besides that, such solution simplifies code and is consistent with the current logic of matcher, which doesn't expect that two members can be matched successfully. Also, it fixes KT-63624 and KT-63667. ^KT-63624 Fixed ^KT-63667 Fixed
This commit is contained in:
committed by
Space Team
parent
3f95e99e29
commit
30aad31ece
+4
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isActual
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isJava
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.getRegularClassSymbolByClassId
|
||||
@@ -435,6 +436,9 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
override val CallableSymbolMarker.hasStableParameterNames: Boolean
|
||||
get() = asSymbol().rawStatus.hasStableParameterNames
|
||||
|
||||
override val CallableSymbolMarker.isJavaField: Boolean
|
||||
get() = this is FirFieldSymbol && fir.isJava
|
||||
|
||||
override val DeclarationSymbolMarker.annotations: List<AnnotationCallInfo>
|
||||
get() = asSymbol().resolvedAnnotationsWithArguments.map(::AnnotationCallInfoImpl)
|
||||
|
||||
|
||||
+3
@@ -492,6 +492,9 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
}
|
||||
}
|
||||
|
||||
override val CallableSymbolMarker.isJavaField: Boolean
|
||||
get() = this is IrFieldSymbol && owner.isFromJava()
|
||||
|
||||
override fun onMatchedMembers(
|
||||
expectSymbol: DeclarationSymbolMarker,
|
||||
actualSymbol: DeclarationSymbolMarker,
|
||||
|
||||
+4
@@ -144,6 +144,10 @@ object AbstractExpectActualMatcher {
|
||||
return ExpectActualMatchingCompatibility.CallableKind
|
||||
}
|
||||
|
||||
if (actualDeclaration.isJavaField) {
|
||||
return ExpectActualMatchingCompatibility.ActualJavaField
|
||||
}
|
||||
|
||||
val expectedReceiverType = expectDeclaration.extensionReceiverType
|
||||
val actualReceiverType = actualDeclaration.extensionReceiverType
|
||||
if ((expectedReceiverType != null) != (actualReceiverType != null)) {
|
||||
|
||||
+2
@@ -163,6 +163,8 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
||||
|
||||
val CallableSymbolMarker.hasStableParameterNames: Boolean
|
||||
|
||||
val CallableSymbolMarker.isJavaField: Boolean
|
||||
|
||||
fun onMatchedMembers(
|
||||
expectSymbol: DeclarationSymbolMarker,
|
||||
actualSymbol: DeclarationSymbolMarker,
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ expect class Foo : I {
|
||||
|
||||
// MODULE: m2-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> = JavaFoo
|
||||
actual typealias Foo = JavaFoo
|
||||
|
||||
// FILE: JavaFoo.java
|
||||
public class JavaFoo implements I {
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
Fails in K2 due to KT-63667
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
expect class Foo {
|
||||
val foo: Int
|
||||
}
|
||||
|
||||
// MODULE: m2-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual typealias Foo = JavaFoo
|
||||
|
||||
interface I {
|
||||
val foo: Int
|
||||
}
|
||||
|
||||
// FILE: JavaFoo.java
|
||||
public class JavaFoo implements I {
|
||||
public final int foo = 1;
|
||||
|
||||
@Override
|
||||
public int getFoo() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
expect class Foo {
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
Fails in K2 due to KT-63667
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
<!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}!>expect class Foo {
|
||||
<!EXPECT_ACTUAL_MISMATCH{JVM}!>var foo: Int<!>
|
||||
}<!>
|
||||
|
||||
// MODULE: m2-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> = JavaFoo
|
||||
|
||||
// FILE: JavaFoo.java
|
||||
public class JavaFoo {
|
||||
public int foo = 0;
|
||||
}
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
expect class Foo {
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
expect class Foo {
|
||||
var foo: Int
|
||||
}
|
||||
|
||||
// MODULE: m2-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> = JavaFoo
|
||||
|
||||
// FILE: JavaFoo.java
|
||||
public class JavaFoo {
|
||||
public int foo = 0;
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
Fails in K2 due to KT-63667
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
expect class Foo {
|
||||
var foo: Int
|
||||
}
|
||||
|
||||
// MODULE: m2-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
interface I {
|
||||
val foo: Int
|
||||
}
|
||||
|
||||
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>Foo<!> = JavaFoo
|
||||
|
||||
// FILE: JavaFoo.java
|
||||
public class JavaFoo implements I {
|
||||
public int foo;
|
||||
|
||||
@Override
|
||||
public int getFoo() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
// MODULE: m1-common
|
||||
// FILE: common.kt
|
||||
expect class Foo {
|
||||
|
||||
+1
@@ -34,6 +34,7 @@ sealed class ExpectActualMatchingCompatibility : ExpectActualCompatibility<Nothi
|
||||
ExpectActualCompatibility.MismatchOrIncompatible<Nothing>
|
||||
|
||||
object CallableKind : Mismatch("callable kinds are different (function vs property)")
|
||||
object ActualJavaField : Mismatch("actualization to Java field is prohibited")
|
||||
object ParameterShape : Mismatch("parameter shapes are different (extension vs non-extension)")
|
||||
object ParameterCount : Mismatch("number of value parameters is different")
|
||||
object FunctionTypeParameterCount : Mismatch(TYPE_PARAMETER_COUNT)
|
||||
|
||||
Reference in New Issue
Block a user