[FIR, IR] Improve expect-actual modality and visibility mismatch error reporting
^KT-30424 Fixed
I checked other ExpectActualCheckingCompatibility and
ExpectActualMatchingCompatibility and I don't think it makes sense to
change them
* ReturnType Return type is already rendered as part of the signature
* ParameterNames Parameter type is already already rendered as part of the signature
* ClassKind Messages like "Expect declaration class kind is 'class'" look weird.
The current message: "class kinds are different (class, interface, object, enum, annotation)" is clear enough
* ... ...
Note: visibility and modality is not rendered as part of the signature,
that's why I explicitly add them in this commit.
diff --git a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualChecker.kt b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualChecker.kt
index 9bb4c43..04f09c7 100644
--- a/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualChecker.kt
+++ b/compiler/resolution.common/src/org/jetbrains/kotlin/resolve/calls/mpp/AbstractExpectActualChecker.kt
@@ -125,12 +125,14 @@
return ExpectActualCheckingCompatibility.ClassTypeParameterCount
}
- if (!areCompatibleModalities(expectClassSymbol.modality, actualClass.modality)) {
- return ExpectActualCheckingCompatibility.Modality
+ val expectModality = expectClassSymbol.modality
+ val actualModality = actualClass.modality
+ if (expectModality != null && actualModality != null && !areCompatibleModalities(expectModality, actualModality)) {
+ return ExpectActualCheckingCompatibility.Modality(expectModality, actualModality)
}
if (!areCompatibleClassVisibilities(expectClassSymbol, actualClass)) {
- return ExpectActualCheckingCompatibility.Visibility
+ return ExpectActualCheckingCompatibility.Visibility(expectClassSymbol.visibility, actualClass.visibility)
}
val substitutor = createExpectActualTypeParameterSubstitutor(
@@ -317,6 +319,8 @@
val expectModality = expectDeclaration.modality
val actualModality = actualDeclaration.modality
if (
+ expectModality != null &&
+ actualModality != null &&
!areCompatibleModalities(
expectModality,
actualModality,
@@ -324,7 +328,7 @@
actualContainingClass?.modality
)
) {
- return ExpectActualCheckingCompatibility.Modality
+ return ExpectActualCheckingCompatibility.Modality(expectModality, actualModality)
}
if (!areCompatibleCallableVisibilities(
@@ -335,7 +339,7 @@
languageVersionSettings
)
) {
- return ExpectActualCheckingCompatibility.Visibility
+ return ExpectActualCheckingCompatibility.Visibility(expectDeclaration.visibility, actualDeclaration.visibility)
}
getTypeParametersVarianceOrReifiedIncompatibility(expectedTypeParameters, actualTypeParameters)?.let { return it }
@@ -418,8 +422,8 @@
}
private fun areCompatibleModalities(
- expectModality: Modality?,
- actualModality: Modality?,
+ expectModality: Modality,
+ actualModality: Modality,
expectContainingClassModality: Modality? = null,
actualContainingClassModality: Modality? = null,
): Boolean {
@@ -537,7 +541,7 @@
!equalBy(expected, actual) { p -> p.isLateinit } -> ExpectActualCheckingCompatibility.PropertyLateinitModifier
expected.isConst && !actual.isConst -> ExpectActualCheckingCompatibility.PropertyConstModifier
!arePropertySettersWithCompatibleVisibilities(expected, actual, expectContainingClass, languageVersionSettings) ->
- ExpectActualCheckingCompatibility.PropertySetterVisibility
+ ExpectActualCheckingCompatibility.PropertySetterVisibility(expected.setter?.visibility, actual.setter?.visibility)
else -> null
}
}
diff --git a/compiler/testData/multiplatform/incompatibleCallables/output.txt b/compiler/testData/multiplatform/incompatibleCallables/output.txt
index 1c4ce51..d4b6b66 100644
--- a/compiler/testData/multiplatform/incompatibleCallables/output.txt
+++ b/compiler/testData/multiplatform/incompatibleCallables/output.txt
@@ -54,7 +54,7 @@
actual fun <K, V> f7() {}
^^
compiler/testData/multiplatform/incompatibleCallables/jvm.kt:17:21: error: 'actual fun f10(): Unit' has no corresponding expected declaration
-The following declaration is incompatible because visibility is different:
+The following declaration is incompatible because visibility is different. Expect declaration visibility is 'public'. Actual declaration visibility is 'internal':
expect fun f10(): Unit
internal actual fun f10() {}
diff --git a/compiler/testData/multiplatform/incompatibleClasses/output.txt b/compiler/testData/multiplatform/incompatibleClasses/output.txt
index d5bd8e4..f46474e 100644
--- a/compiler/testData/multiplatform/incompatibleClasses/output.txt
+++ b/compiler/testData/multiplatform/incompatibleClasses/output.txt
@@ -87,25 +87,25 @@
actual class PAnnotationClass
^^^^^^^^^^^^^^^^
compiler/testData/multiplatform/incompatibleClasses/jvm.kt:7:24: error: 'actual object PublicObject : Any' has no corresponding expected declaration
-The following declaration is incompatible because visibility is different:
+The following declaration is incompatible because visibility is different. Expect declaration visibility is 'public'. Actual declaration visibility is 'internal':
expect object PublicObject : Any
internal actual object PublicObject
^^^^^^^^^^^^
compiler/testData/multiplatform/incompatibleClasses/jvm.kt:10:20: error: 'actual class OpenClass : Any' has no corresponding expected declaration
-The following declaration is incompatible because modality is different:
+The following declaration is incompatible because modality is different. Expect declaration modality is 'open'. Actual declaration modality is 'final':
expect class OpenClass : Any
final actual class OpenClass
^^^^^^^^^
compiler/testData/multiplatform/incompatibleClasses/jvm.kt:11:19: error: 'actual class AbstractClass : Any' has no corresponding expected declaration
-The following declaration is incompatible because modality is different:
+The following declaration is incompatible because modality is different. Expect declaration modality is 'abstract'. Actual declaration modality is 'open':
expect class AbstractClass : Any
open actual class AbstractClass
^^^^^^^^^^^^^
compiler/testData/multiplatform/incompatibleClasses/jvm.kt:12:23: error: 'actual class FinalClass : Any' has no corresponding expected declaration
-The following declaration is incompatible because modality is different:
+The following declaration is incompatible because modality is different. Expect declaration modality is 'final'. Actual declaration modality is 'abstract':
expect class FinalClass : Any
abstract actual class FinalClass
diff --git a/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualCompatibility.kt b/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualCompatibility.kt
index 911df95..10bfa39 100644
--- a/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualCompatibility.kt
+++ b/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualCompatibility.kt
@@ -77,7 +77,14 @@
object PropertyKind : Incompatible<Nothing>("property kinds are different (val vs var)")
object PropertyLateinitModifier : Incompatible<Nothing>("modifiers are different (lateinit)")
object PropertyConstModifier : Incompatible<Nothing>("modifiers are different (const)")
- object PropertySetterVisibility : Incompatible<Nothing>("setter visibility is different")
+ class PropertySetterVisibility(
+ expectVisibility: org.jetbrains.kotlin.descriptors.Visibility?,
+ actualVisibility: org.jetbrains.kotlin.descriptors.Visibility?,
+ ) : Incompatible<Nothing>(
+ "setter visibility is different. " +
+ "Expect declaration setter visibility is '${expectVisibility?.name}'. " +
+ "Actual declaration setter visibility is '${actualVisibility?.name}'"
+ )
// Classifiers
object ClassKind : Incompatible<Nothing>("class kinds are different (class, interface, object, enum, annotation)")
@@ -91,8 +98,22 @@
object EnumEntries : Incompatible<Nothing>("some entries from expected enum are missing in the actual enum")
// Common
- object Modality : Incompatible<Nothing>("modality is different")
- object Visibility : Incompatible<Nothing>("visibility is different")
+ class Modality(
+ expectModality: org.jetbrains.kotlin.descriptors.Modality,
+ actualModality: org.jetbrains.kotlin.descriptors.Modality,
+ ) : Incompatible<Nothing>(
+ "modality is different. " +
+ "Expect declaration modality is '${expectModality.toString().lowercase()}'. " +
+ "Actual declaration modality is '${actualModality.toString().lowercase()}'"
+ )
+ class Visibility(
+ expectVisibility: org.jetbrains.kotlin.descriptors.Visibility,
+ actualVisibility: org.jetbrains.kotlin.descriptors.Visibility,
+ ) : Incompatible<Nothing>(
+ "visibility is different. " +
+ "Expect declaration visibility is '${expectVisibility.name}'. " +
+ "Actual declaration visibility is '${actualVisibility.name}'"
+ )
object ClassTypeParameterUpperBounds : Incompatible<Nothing>(TYPE_PARAMETER_UPPER_BOUNDS)
object TypeParameterVariance : Incompatible<Nothing>("declaration-site variances of type parameters are different")