[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")