K1: Implement a checker that disallows to have different member scopes for expect open and its actual
^KT-22841 Fixed Review: https://jetbrains.team/p/kt/reviews/11603/timeline The commit also introduces `@AllowDifferentMembersInActual` annotation in stdlib which allows to suppress the diagnostic
This commit is contained in:
@@ -846,6 +846,15 @@ public inline fun kotlin.Short.toUShort(): kotlin.UShort
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun <T : kotlin.AutoCloseable?, R> T.use(block: (T) -> R): R
|
||||
|
||||
@kotlin.annotation.Retention(value = AnnotationRetention.SOURCE)
|
||||
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.CLASS, AnnotationTarget.TYPEALIAS})
|
||||
@kotlin.annotation.MustBeDocumented
|
||||
@kotlin.ExperimentalMultiplatform
|
||||
@kotlin.SinceKotlin(version = "1.9")
|
||||
public final annotation class AllowDifferentMembersInActual : kotlin.Annotation {
|
||||
public constructor AllowDifferentMembersInActual()
|
||||
}
|
||||
|
||||
public interface Annotation {
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ package kotlin.collections
|
||||
*
|
||||
* @param E the type of elements contained in the collection. The collection is invariant in its element type.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'checkIsMutable', 'toJSON', etc. members are added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableCollection<E> protected actual constructor() : AbstractCollection<E>(), MutableCollection<E> {
|
||||
|
||||
actual abstract override fun add(element: E): Boolean
|
||||
|
||||
@@ -17,6 +17,7 @@ package kotlin.collections
|
||||
*
|
||||
* @param E the type of elements contained in the list. The list is invariant in its element type.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'removeRange', 'checkIsMutable', etc. members are added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableList<E> protected actual constructor() : AbstractMutableCollection<E>(), MutableList<E> {
|
||||
protected var modCount: Int = 0
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package kotlin.collections
|
||||
* @param K the type of map keys. The map is invariant in its key type.
|
||||
* @param V the type of map values. The map is invariant in its value type.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'createKeysView', 'checkIsMutable', etc. members are added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableMap<K, V> protected actual constructor() : AbstractMap<K, V>(), MutableMap<K, V> {
|
||||
|
||||
internal open fun createKeysView(): MutableSet<K> = HashMapKeysDefault(this)
|
||||
|
||||
@@ -9,6 +9,7 @@ package kotlin.collections
|
||||
*
|
||||
* @param E the type of elements contained in the set. The set is invariant in its element type.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'AbstractMutableCollection` supertype is added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableSet<E> protected actual constructor() : AbstractMutableCollection<E>(), MutableSet<E> {
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,7 @@ public actual interface KClass<T : Any> : KClassifier {
|
||||
* For example, on JVM, [KClass] instances for a primitive type (`int`) and the corresponding wrapper type (`java.lang.Integer`)
|
||||
* are considered equal, because they have the same fully qualified name "kotlin.Int".
|
||||
*/
|
||||
override fun equals(other: Any?): Boolean
|
||||
actual override fun equals(other: Any?): Boolean
|
||||
|
||||
override fun hashCode(): Int
|
||||
actual override fun hashCode(): Int
|
||||
}
|
||||
|
||||
@@ -28,4 +28,6 @@ package kotlin
|
||||
@Suppress("NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS")
|
||||
@SinceKotlin("1.3") public actual typealias ConcurrentModificationException = java.util.ConcurrentModificationException
|
||||
|
||||
@OptIn(ExperimentalMultiplatform::class)
|
||||
@AllowDifferentMembersInActual // New 'reversed', 'thenComparing', etc. members are added compared to the expect declaration
|
||||
@SinceKotlin("1.1") public actual typealias Comparator<T> = java.util.Comparator<T>
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
package kotlin.text
|
||||
|
||||
@OptIn(ExperimentalMultiplatform::class)
|
||||
@AllowDifferentMembersInActual // New 'append' members are added compared to the expect declaration
|
||||
@SinceKotlin("1.1") public actual typealias Appendable = java.lang.Appendable
|
||||
|
||||
@Suppress("ACTUAL_WITHOUT_EXPECT") // TODO: some supertypes are missing
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.AbstractCollection
|
||||
* @param E the type of elements contained in the collection. The collection is invariant in its element type.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@AllowDifferentMembersInActual // New 'AbstractCollection` supertype is added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableCollection<E> protected actual constructor() : MutableCollection<E>, AbstractCollection<E>() {
|
||||
/**
|
||||
* Adds the specified element to the collection.
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.AbstractList
|
||||
* @param E the type of elements contained in the list. The list is invariant in its element type.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@AllowDifferentMembersInActual // New 'AbstractList` supertype is added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableList<E> protected actual constructor() : MutableList<E>, AbstractList<E>() {
|
||||
/**
|
||||
* Replaces the element at the specified position in this list with the specified element.
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.AbstractMap
|
||||
* @param V the type of map values. The map is invariant in its value type.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@AllowDifferentMembersInActual // New 'AbstractMap` supertype is added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableMap<K, V> protected actual constructor() : MutableMap<K, V>, AbstractMap<K, V>() {
|
||||
/**
|
||||
* Associates the specified [value] with the specified [key] in the map.
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.AbstractSet
|
||||
* @param E the type of elements contained in the set. The set is invariant in its element type.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@AllowDifferentMembersInActual // New 'AbstractSet` supertype is added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableSet<E> protected actual constructor() : MutableSet<E>, AbstractSet<E>() {
|
||||
/**
|
||||
* Adds the specified element to the set.
|
||||
|
||||
@@ -10,6 +10,7 @@ package kotlin.reflect
|
||||
*
|
||||
* @param R return type of the callable.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'KAnnotatedElement` supertype is added compared to the expect declaration
|
||||
public actual interface KCallable<out R> : KAnnotatedElement {
|
||||
/**
|
||||
* The name of this callable as it was declared in the source code.
|
||||
|
||||
@@ -13,6 +13,7 @@ package kotlin.reflect
|
||||
*
|
||||
* @param T the type of the class.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // KClass for JVM adds a lot of new members compared to the expect declaration
|
||||
public actual interface KClass<T : Any> : KDeclarationContainer, KAnnotatedElement, KClassifier {
|
||||
/**
|
||||
* The simple name of the class as it was declared in the source code,
|
||||
@@ -151,7 +152,7 @@ public actual interface KClass<T : Any> : KDeclarationContainer, KAnnotatedEleme
|
||||
* For example, on JVM, [KClass] instances for a primitive type (`int`) and the corresponding wrapper type (`java.lang.Integer`)
|
||||
* are considered equal, because they have the same fully qualified name "kotlin.Int".
|
||||
*/
|
||||
override fun equals(other: Any?): Boolean
|
||||
actual override fun equals(other: Any?): Boolean // KT-24971
|
||||
|
||||
override fun hashCode(): Int
|
||||
actual override fun hashCode(): Int // KT-24971
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package kotlin.reflect
|
||||
/**
|
||||
* Represents a function with introspection capabilities.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // KFunction for JVM adds a lot of new members compared to the expect declaration
|
||||
public actual interface KFunction<out R> : KCallable<R>, Function<R> {
|
||||
/**
|
||||
* `true` if this function is `inline`.
|
||||
|
||||
@@ -15,6 +15,7 @@ package kotlin.reflect
|
||||
*
|
||||
* @param V the type of the property value.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // KProperty for JVM adds new members compared to the expect declaration
|
||||
public actual interface KProperty<out V> : KCallable<V> {
|
||||
/**
|
||||
* `true` if this property is `lateinit`.
|
||||
@@ -56,6 +57,7 @@ public actual interface KProperty<out V> : KCallable<V> {
|
||||
/**
|
||||
* Represents a property declared as a `var`.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'setter' member is added compared to the expect declaration
|
||||
public actual interface KMutableProperty<V> : KProperty<V> {
|
||||
/** The setter of this mutable property, used to change the value of the property. */
|
||||
public val setter: Setter<V>
|
||||
@@ -72,6 +74,7 @@ public actual interface KMutableProperty<V> : KProperty<V> {
|
||||
* Such property is either originally declared in a receiverless context such as a package,
|
||||
* or has the receiver bound to it.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'getDelegate' and 'getter' members are added compared to the expect declaration
|
||||
public actual interface KProperty0<out V> : KProperty<V>, () -> V {
|
||||
/**
|
||||
* Returns the current value of the property.
|
||||
@@ -99,6 +102,7 @@ public actual interface KProperty0<out V> : KProperty<V>, () -> V {
|
||||
/**
|
||||
* Represents a `var`-property without any kind of receiver.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // Covariant 'setter' override. The annotations can be dropped in K2 KT-61184
|
||||
public actual interface KMutableProperty0<V> : KProperty0<V>, KMutableProperty<V> {
|
||||
/**
|
||||
* Modifies the value of the property.
|
||||
@@ -124,6 +128,7 @@ public actual interface KMutableProperty0<V> : KProperty0<V>, KMutableProperty<V
|
||||
* @param T the type of the receiver which should be used to obtain the value of the property.
|
||||
* @param V the type of the property value.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'getDelegate' and 'getter' members are added compared to the expect declaration
|
||||
public actual interface KProperty1<T, out V> : KProperty<V>, (T) -> V {
|
||||
/**
|
||||
* Returns the current value of the property.
|
||||
@@ -164,6 +169,7 @@ public actual interface KProperty1<T, out V> : KProperty<V>, (T) -> V {
|
||||
/**
|
||||
* Represents a `var`-property, operations on which take one receiver as a parameter.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // Covariant 'setter' override. The annotations can be dropped in K2 KT-61184
|
||||
public actual interface KMutableProperty1<T, V> : KProperty1<T, V>, KMutableProperty<V> {
|
||||
/**
|
||||
* Modifies the value of the property.
|
||||
@@ -196,6 +202,7 @@ public actual interface KMutableProperty1<T, V> : KProperty1<T, V>, KMutableProp
|
||||
* the type of the extension receiver.
|
||||
* @param V the type of the property value.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'getDelegate' and 'getter' members are added compared to the expect declaration
|
||||
public actual interface KProperty2<D, E, out V> : KProperty<V>, (D, E) -> V {
|
||||
/**
|
||||
* Returns the current value of the property. In case of the extension property in a class,
|
||||
@@ -236,6 +243,7 @@ public actual interface KProperty2<D, E, out V> : KProperty<V>, (D, E) -> V {
|
||||
/**
|
||||
* Represents a `var`-property, operations on which take two receivers as parameters.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // Covariant 'setter' override. The annotations can be dropped in K2 KT-61184
|
||||
public actual interface KMutableProperty2<D, E, V> : KProperty2<D, E, V>, KMutableProperty<V> {
|
||||
/**
|
||||
* Modifies the value of the property.
|
||||
|
||||
@@ -9,6 +9,7 @@ package kotlin.reflect
|
||||
* Represents a type. Type is usually either a class with optional type arguments,
|
||||
* or a type parameter of some declaration, plus nullability.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'KAnnotatedElement` supertype is added compared to the expect declaration
|
||||
public actual interface KType : KAnnotatedElement {
|
||||
/**
|
||||
* The declaration of the classifier used in this type.
|
||||
|
||||
@@ -10,6 +10,7 @@ package kotlin.collections
|
||||
*
|
||||
* @param E the type of elements contained in the collection. The collection is invariant in its element type.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'AbstractCollection` supertype is added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableCollection<E> protected actual constructor(): MutableCollection<E>, AbstractCollection<E>() {
|
||||
|
||||
// Bulk Modification Operations
|
||||
|
||||
@@ -17,6 +17,7 @@ package kotlin.collections
|
||||
*
|
||||
* @param E the type of elements contained in the list. The list is invariant in its element type.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'removeRange', 'modCount' members are added compared to the expect declaration
|
||||
public actual abstract class AbstractMutableList<E> protected actual constructor() : AbstractMutableCollection<E>(), MutableList<E> {
|
||||
/**
|
||||
* The number of times this list is structurally modified.
|
||||
|
||||
@@ -8,6 +8,7 @@ package kotlin.collections
|
||||
* @param K the type of map keys. The map is invariant in its key type.
|
||||
* @param V the type of map values. The map is invariant in its value type.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'AbstractMap` supertype is added compared to the expect declaration
|
||||
@SinceKotlin("1.1")
|
||||
public actual abstract class AbstractMutableMap<K, V> protected actual constructor() : AbstractMap<K, V>(), MutableMap<K, V> {
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@ package kotlin.collections
|
||||
*
|
||||
* @param E the type of elements contained in the set. The set is invariant in its element type.
|
||||
*/
|
||||
@AllowDifferentMembersInActual // New 'AbstractMutableCollection` supertype is added compared to the expect declaration
|
||||
@SinceKotlin("1.1")
|
||||
public actual abstract class AbstractMutableSet<E> protected actual constructor() : AbstractMutableCollection<E>(), MutableSet<E> {
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package kotlin
|
||||
|
||||
import kotlin.annotation.AnnotationTarget.*
|
||||
|
||||
/**
|
||||
* Kotlin reports a compilation error for cases when non-final `expect class` and its counterpart `actual class` have different set of
|
||||
* non-private members (e.g. when a new member declared in `actual class` that wasn't presented in its `expect class`, or when
|
||||
* modality is different).
|
||||
*
|
||||
* By marking `actual class` with this annotation, you suppress the compilation error mentioned above.
|
||||
*
|
||||
* ## Safety Risks
|
||||
*
|
||||
* Using this annotation causes undefined behaviour, it's not known what can break because of that. Be prepared that at some point this
|
||||
* annotation might become deprecated, and you'd need to migrate your code.
|
||||
*
|
||||
* If you use this annotation and can't migrate, consider describing your use cases in
|
||||
* [KT-22841](https://youtrack.jetbrains.com/issue/KT-22841) comments.
|
||||
*
|
||||
* ## Migration
|
||||
*
|
||||
* Please consider the following alternatives:
|
||||
* - Make members in `expect class` and `actual class` the same
|
||||
* - If the member was declared only in `actual class` then you'd need to declare it in the `expect class` as well
|
||||
* - If the member is already declared in the `expect class` then make sure that the member is the same in the `actual class` (modality is
|
||||
* the same, visibility is the same, return type is the same, etc.)
|
||||
* - Make the `expect class` `final`. You might need to rewrite your code to use composition instead of inheritance.
|
||||
* - Mark the members under the question as `private`
|
||||
*
|
||||
* [AllowDifferentMembersInActual] is supposed to be used for the transition period.
|
||||
*/
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@Target(CLASS, TYPEALIAS)
|
||||
@MustBeDocumented
|
||||
@ExperimentalMultiplatform
|
||||
@SinceKotlin("1.9")
|
||||
public annotation class AllowDifferentMembersInActual
|
||||
@@ -32,4 +32,7 @@ public expect interface KClass<T : Any> : KClassifier {
|
||||
@SinceKotlin("1.1")
|
||||
public fun isInstance(value: Any?): Boolean
|
||||
|
||||
override fun equals(other: Any?): Boolean // KT-24971
|
||||
|
||||
override fun hashCode(): Int // KT-24971
|
||||
}
|
||||
@@ -32,4 +32,7 @@ public actual interface KClass<T : Any> : KClassifier {
|
||||
@SinceKotlin("1.1")
|
||||
public actual fun isInstance(value: Any?): Boolean
|
||||
|
||||
actual override fun equals(other: Any?): Boolean // KT-24971
|
||||
|
||||
actual override fun hashCode(): Int // KT-24971
|
||||
}
|
||||
@@ -15,6 +15,9 @@ internal object NothingKClassImpl : KClass<Nothing> {
|
||||
override val qualifiedName: String get() = "kotlin.Nothing"
|
||||
|
||||
override fun isInstance(value: Any?): Boolean = false
|
||||
|
||||
override fun equals(other: Any?): Boolean = super.equals(other) // KT-24971
|
||||
override fun hashCode(): Int = super.hashCode() // KT-24971
|
||||
}
|
||||
|
||||
internal object ErrorKClass : KClass<Nothing> {
|
||||
@@ -22,6 +25,9 @@ internal object ErrorKClass : KClass<Nothing> {
|
||||
override val qualifiedName: String get() = error("Unknown qualifiedName for ErrorKClass")
|
||||
|
||||
override fun isInstance(value: Any?): Boolean = error("Can's check isInstance on ErrorKClass")
|
||||
|
||||
override fun equals(other: Any?): Boolean = super.equals(other) // KT-24971
|
||||
override fun hashCode(): Int = super.hashCode() // KT-24971
|
||||
}
|
||||
|
||||
internal class KClassImpl<T : Any>(internal val typeData: TypeInfoData) : KClass<T> {
|
||||
|
||||
Reference in New Issue
Block a user