[MPP] Fix checkExpectedParameter using wrong ModuleFilter
KT-50120 Partially solved for functions. ClassConstructors seem to be deserialized with 'isExpect=false' which will still lead to wrong 'expect/actual matching'
This commit is contained in:
committed by
Space
parent
017aacba44
commit
e561b095f7
@@ -17,10 +17,11 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
|
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
|
||||||
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.bindingContextUtil.isUsedAsExpression
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
||||||
|
import org.jetbrains.kotlin.resolve.multiplatform.onlyFromThisModule
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.util.getExceptionMessage
|
import org.jetbrains.kotlin.util.getExceptionMessage
|
||||||
import org.jetbrains.kotlin.util.getNonPrivateTraitMembersForDelegation
|
import org.jetbrains.kotlin.util.getNonPrivateTraitMembersForDelegation
|
||||||
@@ -182,7 +183,7 @@ object CodegenUtil {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun findExpectedFunctionForActual(descriptor: FunctionDescriptor): FunctionDescriptor? {
|
fun findExpectedFunctionForActual(descriptor: FunctionDescriptor): FunctionDescriptor? {
|
||||||
val compatibleExpectedFunctions = with(ExpectedActualResolver) {
|
val compatibleExpectedFunctions = with(ExpectedActualResolver) {
|
||||||
descriptor.findCompatibleExpectedForActual(DescriptorUtils.getContainingModule(descriptor))
|
descriptor.findCompatibleExpectedForActual(onlyFromThisModule(descriptor.module))
|
||||||
}
|
}
|
||||||
return compatibleExpectedFunctions.firstOrNull() as FunctionDescriptor?
|
return compatibleExpectedFunctions.firstOrNull() as FunctionDescriptor?
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-10
@@ -30,11 +30,8 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isPrimaryConstructorOfInlineClass
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isPrimaryConstructorOfInlineClass
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
import org.jetbrains.kotlin.resolve.multiplatform.*
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.*
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.*
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ModuleFilter
|
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
|
|
||||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||||
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -69,13 +66,13 @@ class ExpectedActualDeclarationChecker(
|
|||||||
checkActualModifier, context.expectActualTracker
|
checkActualModifier, context.expectActualTracker
|
||||||
)
|
)
|
||||||
} else if (descriptor.isActualOrSomeContainerIsActual()) {
|
} else if (descriptor.isActualOrSomeContainerIsActual()) {
|
||||||
val allImplementedModules = moduleStructureOracle.findAllDependsOnPaths(descriptor.module).flatMap { it.nodes }.toHashSet()
|
val allDependsOnModules = moduleStructureOracle.findAllDependsOnPaths(descriptor.module).flatMap { it.nodes }.toHashSet()
|
||||||
checkActualDeclarationHasExpected(
|
checkActualDeclarationHasExpected(
|
||||||
declaration,
|
declaration,
|
||||||
descriptor,
|
descriptor,
|
||||||
checkActualModifier,
|
checkActualModifier,
|
||||||
context.trace,
|
context.trace,
|
||||||
moduleVisibilityFilter = { it in allImplementedModules }
|
moduleVisibilityFilter = { it in allDependsOnModules }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +219,7 @@ class ExpectedActualDeclarationChecker(
|
|||||||
compatibility: Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>
|
compatibility: Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return compatibility.values.flatMapTo(hashSetOf()) { it }.all { actual ->
|
return compatibility.values.flatMapTo(hashSetOf()) { it }.all { actual ->
|
||||||
val expectedOnes = ExpectedActualResolver.findExpectedForActual(actual, module)
|
val expectedOnes = ExpectedActualResolver.findExpectedForActual(actual, onlyFromThisModule(module))
|
||||||
expectedOnes != null && Compatible in expectedOnes.keys
|
expectedOnes != null && Compatible in expectedOnes.keys
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,7 +247,7 @@ class ExpectedActualDeclarationChecker(
|
|||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
moduleVisibilityFilter: ModuleFilter
|
moduleVisibilityFilter: ModuleFilter
|
||||||
) {
|
) {
|
||||||
val compatibility = ExpectedActualResolver.findExpectedForActual(descriptor, descriptor.module, moduleVisibilityFilter)
|
val compatibility = ExpectedActualResolver.findExpectedForActual(descriptor, moduleVisibilityFilter)
|
||||||
?: return
|
?: return
|
||||||
|
|
||||||
checkAmbiguousExpects(compatibility, trace, reportOn, descriptor)
|
checkAmbiguousExpects(compatibility, trace, reportOn, descriptor)
|
||||||
@@ -290,8 +287,7 @@ class ExpectedActualDeclarationChecker(
|
|||||||
actualMember.isExplicitActualDeclaration() &&
|
actualMember.isExplicitActualDeclaration() &&
|
||||||
!incompatibility.allStrongIncompatibilities() &&
|
!incompatibility.allStrongIncompatibilities() &&
|
||||||
ExpectedActualResolver.findExpectedForActual(
|
ExpectedActualResolver.findExpectedForActual(
|
||||||
actualMember,
|
actualMember, onlyFromThisModule(expectedMember.module)
|
||||||
expectedMember.module
|
|
||||||
)?.values?.singleOrNull()?.singleOrNull() == expectedMember
|
)?.values?.singleOrNull()?.singleOrNull() == expectedMember
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
|
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
|
||||||
|
import org.jetbrains.kotlin.resolve.multiplatform.onlyFromThisModule
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
// `doRemove` means should expect-declaration be removed from IR
|
// `doRemove` means should expect-declaration be removed from IR
|
||||||
@@ -143,7 +144,7 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
|
|||||||
private fun MemberDescriptor.findExpectForActual(): MemberDescriptor? {
|
private fun MemberDescriptor.findExpectForActual(): MemberDescriptor? {
|
||||||
if (!isActual) error(this)
|
if (!isActual) error(this)
|
||||||
return with(ExpectedActualResolver) {
|
return with(ExpectedActualResolver) {
|
||||||
findCompatibleExpectedForActual(this@findExpectForActual.module).singleOrNull()
|
findCompatibleExpectedForActual(onlyFromThisModule(this@findExpectForActual.module)).singleOrNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.resolve.calls.model.CollectionLiteralKotlinCallArgum
|
|||||||
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
|
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isParameterOfAnnotation
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isParameterOfAnnotation
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.multiplatform.ALL_MODULES
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
|
||||||
import org.jetbrains.kotlin.types.UnwrappedType
|
import org.jetbrains.kotlin.types.UnwrappedType
|
||||||
@@ -113,7 +113,7 @@ private fun ValueParameterDescriptor.checkExpectedParameter(checker: (ValueParam
|
|||||||
val function = containingDeclaration
|
val function = containingDeclaration
|
||||||
if (function is FunctionDescriptor && function.isActual) {
|
if (function is FunctionDescriptor && function.isActual) {
|
||||||
with(ExpectedActualResolver) {
|
with(ExpectedActualResolver) {
|
||||||
val expected = function.findCompatibleExpectedForActual(function.module).firstOrNull()
|
val expected = function.findCompatibleExpectedForActual(ALL_MODULES).firstOrNull()
|
||||||
return expected is FunctionDescriptor && checker(expected.valueParameters[index])
|
return expected is FunctionDescriptor && checker(expected.valueParameters[index])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-17
@@ -26,22 +26,22 @@ import org.jetbrains.kotlin.utils.keysToMap
|
|||||||
object ExpectedActualResolver {
|
object ExpectedActualResolver {
|
||||||
// FIXME(dsavvinov): review clients, as they won't work properly in HMPP projects
|
// FIXME(dsavvinov): review clients, as they won't work properly in HMPP projects
|
||||||
fun MemberDescriptor.findCompatibleActualForExpected(platformModule: ModuleDescriptor): List<MemberDescriptor> =
|
fun MemberDescriptor.findCompatibleActualForExpected(platformModule: ModuleDescriptor): List<MemberDescriptor> =
|
||||||
findActualForExpected(this, platformModule)?.get(Compatible).orEmpty()
|
findActualForExpected(this, platformModule, onlyFromThisModule(platformModule))?.get(Compatible).orEmpty()
|
||||||
|
|
||||||
fun MemberDescriptor.findAnyActualForExpected(platformModule: ModuleDescriptor): List<MemberDescriptor> {
|
fun MemberDescriptor.findAnyActualForExpected(platformModule: ModuleDescriptor): List<MemberDescriptor> {
|
||||||
val actualsGroupedByCompatibility = findActualForExpected(this, platformModule)
|
val actualsGroupedByCompatibility = findActualForExpected(this, platformModule, onlyFromThisModule(platformModule))
|
||||||
return actualsGroupedByCompatibility?.get(Compatible)
|
return actualsGroupedByCompatibility?.get(Compatible)
|
||||||
?: actualsGroupedByCompatibility?.values?.flatten()
|
?: actualsGroupedByCompatibility?.values?.flatten()
|
||||||
?: emptyList()
|
?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MemberDescriptor.findCompatibleExpectedForActual(commonModule: ModuleDescriptor): List<MemberDescriptor> =
|
fun MemberDescriptor.findCompatibleExpectedForActual(moduleFilter: ModuleFilter): List<MemberDescriptor> =
|
||||||
findExpectedForActual(this, commonModule)?.get(Compatible).orEmpty()
|
findExpectedForActual(this, moduleFilter)?.get(Compatible).orEmpty()
|
||||||
|
|
||||||
fun findActualForExpected(
|
fun findActualForExpected(
|
||||||
expected: MemberDescriptor,
|
expected: MemberDescriptor,
|
||||||
platformModule: ModuleDescriptor,
|
platformModule: ModuleDescriptor,
|
||||||
moduleVisibilityFilter: ModuleFilter = onlyFromThisModule(platformModule)
|
moduleVisibilityFilter: ModuleFilter,
|
||||||
): Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>? {
|
): Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>? {
|
||||||
return when (expected) {
|
return when (expected) {
|
||||||
is CallableMemberDescriptor -> {
|
is CallableMemberDescriptor -> {
|
||||||
@@ -69,8 +69,7 @@ object ExpectedActualResolver {
|
|||||||
|
|
||||||
fun findExpectedForActual(
|
fun findExpectedForActual(
|
||||||
actual: MemberDescriptor,
|
actual: MemberDescriptor,
|
||||||
commonModule: ModuleDescriptor,
|
moduleFilter: (ModuleDescriptor) -> Boolean
|
||||||
moduleFilter: (ModuleDescriptor) -> Boolean = onlyFromThisModule(commonModule)
|
|
||||||
): Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>? {
|
): Map<ExpectActualCompatibility<MemberDescriptor>, List<MemberDescriptor>>? {
|
||||||
return when (actual) {
|
return when (actual) {
|
||||||
is CallableMemberDescriptor -> {
|
is CallableMemberDescriptor -> {
|
||||||
@@ -79,10 +78,10 @@ object ExpectedActualResolver {
|
|||||||
is ClassifierDescriptorWithTypeParameters -> {
|
is ClassifierDescriptorWithTypeParameters -> {
|
||||||
// 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 expectedClass =
|
val expectedClass =
|
||||||
findExpectedForActual(container, commonModule, moduleFilter)?.values?.firstOrNull()?.firstOrNull() as? ClassDescriptor
|
findExpectedForActual(container, moduleFilter)?.values?.firstOrNull()?.firstOrNull() as? ClassDescriptor
|
||||||
expectedClass?.getMembers(actual.name)?.filterIsInstance<CallableMemberDescriptor>().orEmpty()
|
expectedClass?.getMembers(actual.name)?.filterIsInstance<CallableMemberDescriptor>().orEmpty()
|
||||||
}
|
}
|
||||||
is PackageFragmentDescriptor -> actual.findNamesakesFromModule(commonModule, moduleFilter)
|
is PackageFragmentDescriptor -> actual.findNamesakesFromModule(actual.module, moduleFilter)
|
||||||
else -> return null // do not report anything for incorrect code, e.g. 'actual' local function
|
else -> return null // do not report anything for incorrect code, e.g. 'actual' local function
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +100,7 @@ object ExpectedActualResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is ClassifierDescriptorWithTypeParameters -> {
|
is ClassifierDescriptorWithTypeParameters -> {
|
||||||
actual.findClassifiersFromModule(commonModule, moduleFilter).filter { declaration ->
|
actual.findClassifiersFromModule(actual.module, moduleFilter).filter { declaration ->
|
||||||
actual != declaration &&
|
actual != declaration &&
|
||||||
declaration is ClassDescriptor && declaration.isExpect
|
declaration is ClassDescriptor && declaration.isExpect
|
||||||
}.groupBy { expected ->
|
}.groupBy { expected ->
|
||||||
@@ -534,19 +533,15 @@ object ExpectedActualResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DeclarationDescriptor.findExpects(inModule: ModuleDescriptor = this.module): List<MemberDescriptor> {
|
fun DeclarationDescriptor.findExpects(): List<MemberDescriptor> {
|
||||||
return ExpectedActualResolver.findExpectedForActual(
|
return ExpectedActualResolver.findExpectedForActual(
|
||||||
this as MemberDescriptor,
|
this as MemberDescriptor, ALL_MODULES
|
||||||
inModule,
|
|
||||||
{ true }
|
|
||||||
)?.get(Compatible).orEmpty()
|
)?.get(Compatible).orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun DeclarationDescriptor.findActuals(inModule: ModuleDescriptor = this.module): List<MemberDescriptor> {
|
fun DeclarationDescriptor.findActuals(inModule: ModuleDescriptor = this.module): List<MemberDescriptor> {
|
||||||
return ExpectedActualResolver.findActualForExpected(
|
return ExpectedActualResolver.findActualForExpected(
|
||||||
(this as MemberDescriptor),
|
(this as MemberDescriptor), inModule, ALL_MODULES
|
||||||
inModule,
|
|
||||||
{ true }
|
|
||||||
)?.get(Compatible).orEmpty()
|
)?.get(Compatible).orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user