Don't report incompatibility expect/actual errors on usual overloads
Divide incompatibility on two groups: strong and weak. Strong incompatibility means that if declaration with such incompatibility has no `actual` modifier then it's considered as usual overload and we'll not report any error on it. #KT-20540 Fixed #KT-20680 Fixed
This commit is contained in:
+14
-5
@@ -84,7 +84,7 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
val compatibility = findActualForExpected(descriptor, platformModule) ?: return
|
||||
|
||||
val shouldReportError =
|
||||
compatibility.isEmpty() ||
|
||||
compatibility.allStrongIncompatibilities() ||
|
||||
Compatible !in compatibility && compatibility.values.flatMapTo(hashSetOf()) { it }.all { actual ->
|
||||
val expectedOnes = findExpectedForActual(actual, descriptor.module)
|
||||
expectedOnes != null && Compatible in expectedOnes.keys
|
||||
@@ -98,6 +98,9 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
}
|
||||
|
||||
fun Map<out Compatibility, Collection<MemberDescriptor>>.allStrongIncompatibilities(): Boolean =
|
||||
this.keys.all { it is Incompatible && it.kind == Compatibility.IncompatibilityKind.STRONG }
|
||||
|
||||
private fun findActualForExpected(expected: MemberDescriptor, platformModule: ModuleDescriptor): Map<Compatibility, List<MemberDescriptor>>? {
|
||||
return when (expected) {
|
||||
is CallableMemberDescriptor -> {
|
||||
@@ -131,7 +134,7 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
|
||||
val hasActualModifier = descriptor.isActual && reportOn.hasActualModifier()
|
||||
if (!hasActualModifier) {
|
||||
if (compatibility.isEmpty()) return
|
||||
if (compatibility.allStrongIncompatibilities()) return
|
||||
|
||||
if (Compatible in compatibility) {
|
||||
// we suppress error, because annotation classes can only have one constructor and it's a 100% boilerplate
|
||||
@@ -163,6 +166,7 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
val actualMember = incompatibility.values.singleOrNull()?.singleOrNull()
|
||||
return actualMember != null &&
|
||||
actualMember.isExplicitActualDeclaration() &&
|
||||
!incompatibility.allStrongIncompatibilities() &&
|
||||
findExpectedForActual(actualMember, expectedMember.module)?.values?.singleOrNull()?.singleOrNull() == expectedMember
|
||||
}
|
||||
|
||||
@@ -293,16 +297,21 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
|
||||
sealed class Compatibility {
|
||||
// For IncompatibilityKind.STRONG `actual` declaration is considered as overload and error reports on expected declaration
|
||||
enum class IncompatibilityKind {
|
||||
WEAK, STRONG
|
||||
}
|
||||
|
||||
// Note that the reason is used in the diagnostic output, see PlatformIncompatibilityDiagnosticRenderer
|
||||
sealed class Incompatible(val reason: String?) : Compatibility() {
|
||||
sealed class Incompatible(val reason: String?, val kind: IncompatibilityKind = IncompatibilityKind.WEAK) : Compatibility() {
|
||||
// Callables
|
||||
|
||||
object ParameterShape : Incompatible("parameter shapes are different (extension vs non-extension)")
|
||||
|
||||
object ParameterCount : Incompatible("number of value parameters is different")
|
||||
object ParameterCount : Incompatible("number of value parameters is different", IncompatibilityKind.STRONG)
|
||||
object TypeParameterCount : Incompatible("number of type parameters is different")
|
||||
|
||||
object ParameterTypes : Incompatible("parameter types are different")
|
||||
object ParameterTypes : Incompatible("parameter types are different", IncompatibilityKind.STRONG)
|
||||
object ReturnType : Incompatible("return type is different")
|
||||
|
||||
object ParameterNames : Incompatible("parameter names are different")
|
||||
|
||||
Reference in New Issue
Block a user