[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:
sebastian.sellmair
2021-12-15 16:19:47 +01:00
committed by Space
parent 017aacba44
commit e561b095f7
5 changed files with 25 additions and 32 deletions
@@ -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?
} }
@@ -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
} }
@@ -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()
} }
} }
@@ -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])
} }
} }
@@ -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()
} }