Migration to expect/actual: ExpectedActualDeclarationChecker
This commit is contained in:
+2
-2
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.load.java.sam.SamConversionResolverImpl
|
|||||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||||
import org.jetbrains.kotlin.resolve.PlatformConfigurator
|
import org.jetbrains.kotlin.resolve.PlatformConfigurator
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.ReifiedTypeParameterSubstitutionChecker
|
import org.jetbrains.kotlin.resolve.calls.checkers.ReifiedTypeParameterSubstitutionChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.HeaderImplDeclarationChecker
|
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||||
import org.jetbrains.kotlin.resolve.jvm.*
|
import org.jetbrains.kotlin.resolve.jvm.*
|
||||||
import org.jetbrains.kotlin.resolve.jvm.checkers.*
|
import org.jetbrains.kotlin.resolve.jvm.checkers.*
|
||||||
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
|
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
|
||||||
@@ -43,7 +43,7 @@ object JvmPlatformConfigurator : PlatformConfigurator(
|
|||||||
TypeParameterBoundIsNotArrayChecker(),
|
TypeParameterBoundIsNotArrayChecker(),
|
||||||
JvmSyntheticApplicabilityChecker(),
|
JvmSyntheticApplicabilityChecker(),
|
||||||
StrictfpApplicabilityChecker(),
|
StrictfpApplicabilityChecker(),
|
||||||
HeaderImplDeclarationChecker
|
ExpectedActualDeclarationChecker
|
||||||
),
|
),
|
||||||
|
|
||||||
additionalCallCheckers = listOf(
|
additionalCallCheckers = listOf(
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
|
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier;
|
import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier;
|
||||||
import org.jetbrains.kotlin.resolve.checkers.HeaderImplDeclarationChecker.Compatibility.Incompatible;
|
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker.Compatibility.Incompatible;
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData;
|
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData;
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.SinceKotlinInfo;
|
import org.jetbrains.kotlin.serialization.deserialization.descriptors.SinceKotlinInfo;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.diagnostics.rendering
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.checkers.HeaderImplDeclarationChecker.Compatibility.Incompatible
|
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker.Compatibility.Incompatible
|
||||||
|
|
||||||
class PlatformIncompatibilityDiagnosticRenderer(
|
class PlatformIncompatibilityDiagnosticRenderer(
|
||||||
private val mode: MultiplatformDiagnosticRenderingMode
|
private val mode: MultiplatformDiagnosticRenderingMode
|
||||||
|
|||||||
+76
-76
@@ -32,8 +32,8 @@ import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.checkers.HeaderImplDeclarationChecker.Compatibility.Compatible
|
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker.Compatibility.Compatible
|
||||||
import org.jetbrains.kotlin.resolve.checkers.HeaderImplDeclarationChecker.Compatibility.Incompatible
|
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker.Compatibility.Incompatible
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
@@ -49,7 +49,7 @@ import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
|||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
import org.jetbrains.kotlin.utils.keysToMap
|
import org.jetbrains.kotlin.utils.keysToMap
|
||||||
|
|
||||||
object HeaderImplDeclarationChecker : DeclarationChecker {
|
object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||||
override fun check(
|
override fun check(
|
||||||
declaration: KtDeclaration,
|
declaration: KtDeclaration,
|
||||||
descriptor: DeclarationDescriptor,
|
descriptor: DeclarationDescriptor,
|
||||||
@@ -62,15 +62,15 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
if (descriptor !is MemberDescriptor || DescriptorUtils.isEnumEntry(descriptor)) return
|
if (descriptor !is MemberDescriptor || DescriptorUtils.isEnumEntry(descriptor)) return
|
||||||
|
|
||||||
if (descriptor.isExpect) {
|
if (descriptor.isExpect) {
|
||||||
checkHeaderDeclarationHasImplementation(declaration, descriptor, diagnosticHolder, descriptor.module)
|
checkExpectedDeclarationHasActual(declaration, descriptor, diagnosticHolder, descriptor.module)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val checkImpl = !languageVersionSettings.getFlag(AnalysisFlag.multiPlatformDoNotCheckImpl)
|
val checkExpected = !languageVersionSettings.getFlag(AnalysisFlag.multiPlatformDoNotCheckImpl)
|
||||||
checkImplementationHasHeaderDeclaration(declaration, descriptor, diagnosticHolder, checkImpl)
|
checkActualDeclarationHasExpected(declaration, descriptor, diagnosticHolder, checkExpected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkHeaderDeclarationHasImplementation(
|
fun checkExpectedDeclarationHasActual(
|
||||||
reportOn: KtDeclaration,
|
reportOn: KtDeclaration,
|
||||||
descriptor: MemberDescriptor,
|
descriptor: MemberDescriptor,
|
||||||
diagnosticHolder: DiagnosticSink,
|
diagnosticHolder: DiagnosticSink,
|
||||||
@@ -79,13 +79,13 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
// Only look for implementations of top level members; class members will be handled as a part of that header class
|
// Only look for implementations of top level members; class members will be handled as a part of that header class
|
||||||
if (descriptor.containingDeclaration !is PackageFragmentDescriptor) return
|
if (descriptor.containingDeclaration !is PackageFragmentDescriptor) return
|
||||||
|
|
||||||
val compatibility = findImplForHeader(descriptor, platformModule) ?: return
|
val compatibility = findActualForExpected(descriptor, platformModule) ?: return
|
||||||
|
|
||||||
val shouldReportError =
|
val shouldReportError =
|
||||||
compatibility.isEmpty() ||
|
compatibility.isEmpty() ||
|
||||||
Compatible !in compatibility && compatibility.values.flatMapTo(hashSetOf()) { it }.all { impl ->
|
Compatible !in compatibility && compatibility.values.flatMapTo(hashSetOf()) { it }.all { actual ->
|
||||||
val headers = findHeaderForImpl(impl, descriptor.module)
|
val expectedOnes = findExpectedForActual(actual, descriptor.module)
|
||||||
headers != null && Compatible in headers.keys
|
expectedOnes != null && Compatible in expectedOnes.keys
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldReportError) {
|
if (shouldReportError) {
|
||||||
@@ -96,42 +96,42 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findImplForHeader(header: MemberDescriptor, platformModule: ModuleDescriptor): Map<Compatibility, List<MemberDescriptor>>? {
|
private fun findActualForExpected(expected: MemberDescriptor, platformModule: ModuleDescriptor): Map<Compatibility, List<MemberDescriptor>>? {
|
||||||
return when (header) {
|
return when (expected) {
|
||||||
is CallableMemberDescriptor -> {
|
is CallableMemberDescriptor -> {
|
||||||
header.findNamesakesFromModule(platformModule).filter { impl ->
|
expected.findNamesakesFromModule(platformModule).filter { actual ->
|
||||||
header != impl && !impl.isExpect &&
|
expected != actual && !actual.isExpect &&
|
||||||
// TODO: support non-source definitions (e.g. from Java)
|
// TODO: support non-source definitions (e.g. from Java)
|
||||||
DescriptorToSourceUtils.getSourceFromDescriptor(impl) is KtElement
|
DescriptorToSourceUtils.getSourceFromDescriptor(actual) is KtElement
|
||||||
}.groupBy { impl ->
|
}.groupBy { actual ->
|
||||||
areCompatibleCallables(header, impl)
|
areCompatibleCallables(expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ClassDescriptor -> {
|
is ClassDescriptor -> {
|
||||||
header.findClassifiersFromModule(platformModule).filter { impl ->
|
expected.findClassifiersFromModule(platformModule).filter { actual ->
|
||||||
header != impl && !impl.isExpect &&
|
expected != actual && !actual.isExpect &&
|
||||||
DescriptorToSourceUtils.getSourceFromDescriptor(impl) is KtElement
|
DescriptorToSourceUtils.getSourceFromDescriptor(actual) is KtElement
|
||||||
}.groupBy { impl ->
|
}.groupBy { actual ->
|
||||||
areCompatibleClassifiers(header, impl)
|
areCompatibleClassifiers(expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkImplementationHasHeaderDeclaration(
|
private fun checkActualDeclarationHasExpected(
|
||||||
reportOn: KtDeclaration, descriptor: MemberDescriptor, diagnosticHolder: DiagnosticSink, checkImpl: Boolean
|
reportOn: KtDeclaration, descriptor: MemberDescriptor, diagnosticHolder: DiagnosticSink, checkExpected: Boolean
|
||||||
) {
|
) {
|
||||||
// Using the platform module instead of the common module is sort of fine here because the former always depends on the latter.
|
// Using the platform module instead of the common module is sort of fine here because the former always depends on the latter.
|
||||||
// However, it would be clearer to find the common module this platform module implements and look for headers there instead.
|
// However, it would be clearer to find the common module this platform module implements and look for headers there instead.
|
||||||
// TODO: use common module here
|
// TODO: use common module here
|
||||||
val compatibility = findHeaderForImpl(descriptor, descriptor.module) ?: return
|
val compatibility = findExpectedForActual(descriptor, descriptor.module) ?: return
|
||||||
|
|
||||||
val hasImplModifier = descriptor.isActual && reportOn.hasActualModifier()
|
val hasExpectedModifier = descriptor.isActual && reportOn.hasActualModifier()
|
||||||
if (!hasImplModifier) {
|
if (!hasExpectedModifier) {
|
||||||
if (Compatible !in compatibility) return
|
if (Compatible !in compatibility) return
|
||||||
|
|
||||||
if (checkImpl) {
|
if (checkExpected) {
|
||||||
diagnosticHolder.report(Errors.IMPL_MISSING.on(reportOn))
|
diagnosticHolder.report(Errors.IMPL_MISSING.on(reportOn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,17 +148,17 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
// (albeit maybe incompatible) single implementation suspect, declared in the impl class.
|
// (albeit maybe incompatible) single implementation suspect, declared in the impl class.
|
||||||
// This is needed only to reduce the number of errors. Incompatibility errors for those members will be reported
|
// This is needed only to reduce the number of errors. Incompatibility errors for those members will be reported
|
||||||
// later when this checker is called for them
|
// later when this checker is called for them
|
||||||
fun hasSingleImplSuspect(
|
fun hasSingleActualSuspect(
|
||||||
headerWithIncompatibility: Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>
|
expectedWithIncompatibility: Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val (headerMember, incompatibility) = headerWithIncompatibility
|
val (expectedMember, incompatibility) = expectedWithIncompatibility
|
||||||
val implMember = incompatibility.values.singleOrNull()?.singleOrNull()
|
val actualMember = incompatibility.values.singleOrNull()?.singleOrNull()
|
||||||
return implMember != null &&
|
return actualMember != null &&
|
||||||
implMember.isExplicitImplDeclaration() &&
|
actualMember.isExplicitActualDeclaration() &&
|
||||||
findHeaderForImpl(implMember, headerMember.module)?.values?.singleOrNull()?.singleOrNull() == headerMember
|
findExpectedForActual(actualMember, expectedMember.module)?.values?.singleOrNull()?.singleOrNull() == expectedMember
|
||||||
}
|
}
|
||||||
|
|
||||||
val nonTrivialUnimplemented = singleIncompatibility.unimplemented.filterNot(::hasSingleImplSuspect)
|
val nonTrivialUnimplemented = singleIncompatibility.unimplemented.filterNot(::hasSingleActualSuspect)
|
||||||
|
|
||||||
if (nonTrivialUnimplemented.isNotEmpty()) {
|
if (nonTrivialUnimplemented.isNotEmpty()) {
|
||||||
val classDescriptor =
|
val classDescriptor =
|
||||||
@@ -179,65 +179,65 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
|
|
||||||
// This should ideally be handled by CallableMemberDescriptor.Kind, but default constructors have kind DECLARATION and non-empty source.
|
// This should ideally be handled by CallableMemberDescriptor.Kind, but default constructors have kind DECLARATION and non-empty source.
|
||||||
// Their source is the containing KtClass instance though, as opposed to explicit constructors, whose source is KtConstructor
|
// Their source is the containing KtClass instance though, as opposed to explicit constructors, whose source is KtConstructor
|
||||||
private fun MemberDescriptor.isExplicitImplDeclaration(): Boolean =
|
private fun MemberDescriptor.isExplicitActualDeclaration(): Boolean =
|
||||||
when (this) {
|
when (this) {
|
||||||
is ConstructorDescriptor -> DescriptorToSourceUtils.getSourceFromDescriptor(this) is KtConstructor<*>
|
is ConstructorDescriptor -> DescriptorToSourceUtils.getSourceFromDescriptor(this) is KtConstructor<*>
|
||||||
is CallableMemberDescriptor -> kind == CallableMemberDescriptor.Kind.DECLARATION
|
is CallableMemberDescriptor -> kind == CallableMemberDescriptor.Kind.DECLARATION
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findHeaderForImpl(impl: MemberDescriptor, commonModule: ModuleDescriptor): Map<Compatibility, List<MemberDescriptor>>? {
|
private fun findExpectedForActual(actual: MemberDescriptor, commonModule: ModuleDescriptor): Map<Compatibility, List<MemberDescriptor>>? {
|
||||||
return when (impl) {
|
return when (actual) {
|
||||||
is CallableMemberDescriptor -> {
|
is CallableMemberDescriptor -> {
|
||||||
val container = impl.containingDeclaration
|
val container = actual.containingDeclaration
|
||||||
val candidates = when (container) {
|
val candidates = when (container) {
|
||||||
is ClassDescriptor -> {
|
is ClassDescriptor -> {
|
||||||
// TODO: replace with 'singleOrNull' as soon as multi-module diagnostic tests are refactored
|
// TODO: replace with 'singleOrNull' as soon as multi-module diagnostic tests are refactored
|
||||||
val headerClass = findHeaderForImpl(container, commonModule)?.values?.firstOrNull()?.firstOrNull() as? ClassDescriptor
|
val expectedClass = findExpectedForActual(container, commonModule)?.values?.firstOrNull()?.firstOrNull() as? ClassDescriptor
|
||||||
headerClass?.getMembers(impl.name)?.filterIsInstance<CallableMemberDescriptor>().orEmpty()
|
expectedClass?.getMembers(actual.name)?.filterIsInstance<CallableMemberDescriptor>().orEmpty()
|
||||||
}
|
}
|
||||||
is PackageFragmentDescriptor -> impl.findNamesakesFromModule(commonModule)
|
is PackageFragmentDescriptor -> actual.findNamesakesFromModule(commonModule)
|
||||||
else -> return null // do not report anything for incorrect code, e.g. 'impl' local function
|
else -> return null // do not report anything for incorrect code, e.g. 'impl' local function
|
||||||
}
|
}
|
||||||
|
|
||||||
candidates.filter { declaration ->
|
candidates.filter { declaration ->
|
||||||
impl != declaration && declaration.isExpect
|
actual != declaration && declaration.isExpect
|
||||||
}.groupBy { declaration ->
|
}.groupBy { declaration ->
|
||||||
// TODO: optimize by caching this per impl-header class pair, do not create a new substitutor for each impl member
|
// TODO: optimize by caching this per impl-header class pair, do not create a new substitutor for each impl member
|
||||||
val substitutor =
|
val substitutor =
|
||||||
if (container is ClassDescriptor) {
|
if (container is ClassDescriptor) {
|
||||||
val headerClass = declaration.containingDeclaration as ClassDescriptor
|
val expectedClass = declaration.containingDeclaration as ClassDescriptor
|
||||||
// TODO: this might not work for members of inner generic classes
|
// TODO: this might not work for members of inner generic classes
|
||||||
Substitutor(headerClass.declaredTypeParameters, container.declaredTypeParameters)
|
Substitutor(expectedClass.declaredTypeParameters, container.declaredTypeParameters)
|
||||||
}
|
}
|
||||||
else null
|
else null
|
||||||
areCompatibleCallables(declaration, impl, parentSubstitutor = substitutor)
|
areCompatibleCallables(declaration, actual, parentSubstitutor = substitutor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ClassifierDescriptorWithTypeParameters -> {
|
is ClassifierDescriptorWithTypeParameters -> {
|
||||||
impl.findClassifiersFromModule(commonModule).filter { declaration ->
|
actual.findClassifiersFromModule(commonModule).filter { declaration ->
|
||||||
impl != declaration &&
|
actual != declaration &&
|
||||||
declaration is ClassDescriptor && declaration.isExpect
|
declaration is ClassDescriptor && declaration.isExpect
|
||||||
}.groupBy { header ->
|
}.groupBy { expected ->
|
||||||
areCompatibleClassifiers(header as ClassDescriptor, impl)
|
areCompatibleClassifiers(expected as ClassDescriptor, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MemberDescriptor.findCompatibleImplForHeader(platformModule: ModuleDescriptor): List<MemberDescriptor> =
|
fun MemberDescriptor.findCompatibleActualForExpected(platformModule: ModuleDescriptor): List<MemberDescriptor> =
|
||||||
findImplForHeader(this, platformModule)?.get(Compatible).orEmpty()
|
findActualForExpected(this, platformModule)?.get(Compatible).orEmpty()
|
||||||
|
|
||||||
fun MemberDescriptor.findAnyImplForHeader(platformModule: ModuleDescriptor): List<MemberDescriptor> {
|
fun MemberDescriptor.findAnyActualForExpected(platformModule: ModuleDescriptor): List<MemberDescriptor> {
|
||||||
val implsGroupedByCompatibility = findImplForHeader(this, platformModule)
|
val actualsGroupedByCompatibility = findActualForExpected(this, platformModule)
|
||||||
return implsGroupedByCompatibility?.get(Compatible)
|
return actualsGroupedByCompatibility?.get(Compatible)
|
||||||
?: implsGroupedByCompatibility?.values?.flatten()
|
?: actualsGroupedByCompatibility?.values?.flatten()
|
||||||
?: emptyList()
|
?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MemberDescriptor.findCompatibleHeaderForImpl(commonModule: ModuleDescriptor): List<MemberDescriptor> =
|
fun MemberDescriptor.findCompatibleExpectedForActual(commonModule: ModuleDescriptor): List<MemberDescriptor> =
|
||||||
findHeaderForImpl(this, commonModule)?.get(Compatible).orEmpty()
|
findExpectedForActual(this, commonModule)?.get(Compatible).orEmpty()
|
||||||
|
|
||||||
private fun CallableMemberDescriptor.findNamesakesFromModule(module: ModuleDescriptor): Collection<CallableMemberDescriptor> {
|
private fun CallableMemberDescriptor.findNamesakesFromModule(module: ModuleDescriptor): Collection<CallableMemberDescriptor> {
|
||||||
val containingDeclaration = containingDeclaration
|
val containingDeclaration = containingDeclaration
|
||||||
@@ -308,7 +308,7 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
object FunctionModifiersDifferent : Incompatible("modifiers are different (suspend)")
|
object FunctionModifiersDifferent : Incompatible("modifiers are different (suspend)")
|
||||||
object FunctionModifiersNotSubset : Incompatible("some modifiers on header declaration are missing on the implementation (external, infix, inline, operator, tailrec)")
|
object FunctionModifiersNotSubset : Incompatible("some modifiers on expected declaration are missing on the actual one (external, infix, inline, operator, tailrec)")
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
|
|
||||||
@@ -321,13 +321,13 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
|
|
||||||
object ClassModifiers : Incompatible("modifiers are different (companion, inner)")
|
object ClassModifiers : Incompatible("modifiers are different (companion, inner)")
|
||||||
|
|
||||||
object Supertypes : Incompatible("some supertypes are missing in the implementation")
|
object Supertypes : Incompatible("some supertypes are missing in the actual declaration")
|
||||||
|
|
||||||
class ClassScopes(
|
class ClassScopes(
|
||||||
val unimplemented: List<Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>>
|
val unimplemented: List<Pair<MemberDescriptor, Map<Incompatible, Collection<MemberDescriptor>>>>
|
||||||
) : Incompatible("some members are not implemented")
|
) : Incompatible("some members are not implemented")
|
||||||
|
|
||||||
object EnumEntries : Incompatible("some entries from header enum are missing in the impl enum")
|
object EnumEntries : Incompatible("some entries from expected enum are missing in the actual enum")
|
||||||
|
|
||||||
// Common
|
// Common
|
||||||
|
|
||||||
@@ -408,8 +408,8 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
with(NewKotlinTypeChecker) {
|
with(NewKotlinTypeChecker) {
|
||||||
val context = object : TypeCheckerContext(false) {
|
val context = object : TypeCheckerContext(false) {
|
||||||
override fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
|
override fun areEqualTypeConstructors(a: TypeConstructor, b: TypeConstructor): Boolean {
|
||||||
return isExpectClassAndImplTypeAlias(a, b, platformModule) ||
|
return isExpectedClassAndActualTypeAlias(a, b, platformModule) ||
|
||||||
isExpectClassAndImplTypeAlias(b, a, platformModule) ||
|
isExpectedClassAndActualTypeAlias(b, a, platformModule) ||
|
||||||
super.areEqualTypeConstructors(a, b)
|
super.areEqualTypeConstructors(a, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,21 +421,21 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
// is java.lang.StringBuilder. For the purposes of type compatibility checking, we must consider these types equal here.
|
// is java.lang.StringBuilder. For the purposes of type compatibility checking, we must consider these types equal here.
|
||||||
// Note that the case of an "impl class" works as expected though, because the impl class by definition has the same FQ name
|
// Note that the case of an "impl class" works as expected though, because the impl class by definition has the same FQ name
|
||||||
// as the corresponding header class, so their type constructors are equal as per AbstractClassTypeConstructor#equals
|
// as the corresponding header class, so their type constructors are equal as per AbstractClassTypeConstructor#equals
|
||||||
private fun isExpectClassAndImplTypeAlias(
|
private fun isExpectedClassAndActualTypeAlias(
|
||||||
headerTypeConstructor: TypeConstructor,
|
expectedTypeConstructor: TypeConstructor,
|
||||||
implTypeConstructor: TypeConstructor,
|
actualTypeConstructor: TypeConstructor,
|
||||||
platformModule: ModuleDescriptor
|
platformModule: ModuleDescriptor
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val header = headerTypeConstructor.declarationDescriptor
|
val expected = expectedTypeConstructor.declarationDescriptor
|
||||||
val impl = implTypeConstructor.declarationDescriptor
|
val actual = actualTypeConstructor.declarationDescriptor
|
||||||
return header is ClassifierDescriptorWithTypeParameters &&
|
return expected is ClassifierDescriptorWithTypeParameters &&
|
||||||
header.isExpect &&
|
expected.isExpect &&
|
||||||
impl is ClassifierDescriptorWithTypeParameters &&
|
actual is ClassifierDescriptorWithTypeParameters &&
|
||||||
header.findClassifiersFromModule(platformModule).any { classifier ->
|
expected.findClassifiersFromModule(platformModule).any { classifier ->
|
||||||
// Note that it's fine to only check that this "impl typealias" expands to the expected class, without checking
|
// Note that it's fine to only check that this "impl typealias" expands to the expected class, without checking
|
||||||
// whether the type arguments in the expansion are in the correct order or have the correct variance, because we only
|
// whether the type arguments in the expansion are in the correct order or have the correct variance, because we only
|
||||||
// allow simple cases like "impl typealias Foo<A, B> = FooImpl<A, B>", see DeclarationsChecker#checkImplTypeAlias
|
// allow simple cases like "impl typealias Foo<A, B> = FooImpl<A, B>", see DeclarationsChecker#checkImplTypeAlias
|
||||||
(classifier as? TypeAliasDescriptor)?.classDescriptor == impl
|
(classifier as? TypeAliasDescriptor)?.classDescriptor == actual
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,7 +488,7 @@ object HeaderImplDeclarationChecker : DeclarationChecker {
|
|||||||
val b = when (other) {
|
val b = when (other) {
|
||||||
is ClassDescriptor -> other
|
is ClassDescriptor -> other
|
||||||
is TypeAliasDescriptor -> other.classDescriptor ?: return Compatible // do not report extra error on erroneous typealias
|
is TypeAliasDescriptor -> other.classDescriptor ?: return Compatible // do not report extra error on erroneous typealias
|
||||||
else -> throw AssertionError("Incorrect impl classifier for $a: $other")
|
else -> throw AssertionError("Incorrect actual classifier for $a: $other")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.kind != b.kind) return Incompatible.ClassKind
|
if (a.kind != b.kind) return Incompatible.ClassKind
|
||||||
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.resolve.OverloadFilter
|
|||||||
import org.jetbrains.kotlin.resolve.OverridesBackwardCompatibilityHelper
|
import org.jetbrains.kotlin.resolve.OverridesBackwardCompatibilityHelper
|
||||||
import org.jetbrains.kotlin.resolve.PlatformConfigurator
|
import org.jetbrains.kotlin.resolve.PlatformConfigurator
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.ReifiedTypeParameterSubstitutionChecker
|
import org.jetbrains.kotlin.resolve.calls.checkers.ReifiedTypeParameterSubstitutionChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.HeaderImplDeclarationChecker
|
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||||
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
|
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
|
||||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||||
import org.jetbrains.kotlin.types.DynamicTypesAllowed
|
import org.jetbrains.kotlin.types.DynamicTypesAllowed
|
||||||
@@ -38,7 +38,7 @@ object JsPlatformConfigurator : PlatformConfigurator(
|
|||||||
JsExternalChecker, JsInheritanceChecker,
|
JsExternalChecker, JsInheritanceChecker,
|
||||||
JsRuntimeAnnotationChecker,
|
JsRuntimeAnnotationChecker,
|
||||||
JsDynamicDeclarationChecker,
|
JsDynamicDeclarationChecker,
|
||||||
HeaderImplDeclarationChecker
|
ExpectedActualDeclarationChecker
|
||||||
),
|
),
|
||||||
additionalCallCheckers = listOf(
|
additionalCallCheckers = listOf(
|
||||||
ReifiedTypeParameterSubstitutionChecker(),
|
ReifiedTypeParameterSubstitutionChecker(),
|
||||||
|
|||||||
Reference in New Issue
Block a user