[FE 1.0] Refactor: extract logic of matching actual against potential expects

Will be needed in subsequent commits for the annotation checker.
`findExpectForActual` is not suitable for the checker because
`findExpectForActual` searches expect class with same `ClassId` for
actual class containing current member (see method
`findClassifiersFromModule`), which is:
1. Unnecessary, since we already have expect class in annotation checker
2. Incorrect when class actualized via typealias and `ClassId` is
   different.

So, it is needed to extract logic of searching potential expects
for actual member and already known expect class.

^KT-60668
^KT-60936
This commit is contained in:
Roman Efremov
2023-08-04 13:04:55 +02:00
committed by Space Team
parent 8aa3ccd342
commit d614f06259
@@ -77,53 +77,71 @@ object ExpectedActualResolver {
else -> return null // do not report anything for incorrect code, e.g. 'actual' local function
}
candidates.filter { declaration ->
actual != declaration && declaration.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE && declaration.isExpect
}.groupBy { declaration ->
// TODO: optimize by caching this per actual-expected class pair, do not create a new substitutor for each actual member
var expectedClass: ClassDescriptor? = null
var actualClass: ClassDescriptor? = null
val substitutor =
when (container) {
is ClassDescriptor -> {
actualClass = container
expectedClass = declaration.containingDeclaration as ClassDescriptor
// TODO: this might not work for members of inner generic classes
runIf(expectedClass.declaredTypeParameters.size == container.declaredTypeParameters.size) {
context.createExpectActualTypeParameterSubstitutor(
expectedClass.declaredTypeParameters,
container.declaredTypeParameters,
parentSubstitutor = null
)
}
}
else -> null
}
AbstractExpectActualCompatibilityChecker.getCallablesCompatibility(
expectDeclaration = declaration,
actualDeclaration = actual,
parentSubstitutor = substitutor,
expectContainingClass = expectedClass,
actualContainingClass = actualClass,
context
)
}
matchActualCallableAgainstPotentialExpects(actual, candidates, container, context)
}
is ClassifierDescriptorWithTypeParameters -> {
context.findClassifiersFromModule(actual.classId, actual.module, moduleFilter).filter { declaration ->
actual != declaration && declaration is ClassDescriptor && declaration.isExpect
}.groupBy { expected ->
AbstractExpectActualCompatibilityChecker.getClassifiersCompatibility(
expected as ClassDescriptor,
actual,
context
)
}
val candidates = context.findClassifiersFromModule(actual.classId, actual.module, moduleFilter)
matchActualClassAgainstPotentialExpects(actual, candidates, context)
}
else -> null
}
}
private fun matchActualCallableAgainstPotentialExpects(
actual: CallableMemberDescriptor,
candidates: Collection<CallableMemberDescriptor>,
container: DeclarationDescriptor,
context: ClassicExpectActualMatchingContext,
): Map<ExpectActualCompatibility<MemberDescriptor>, List<CallableMemberDescriptor>> {
return candidates.filter { declaration ->
actual != declaration && declaration.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE && declaration.isExpect
}.groupBy { declaration ->
// TODO: optimize by caching this per actual-expected class pair, do not create a new substitutor for each actual member
var expectedClass: ClassDescriptor? = null
var actualClass: ClassDescriptor? = null
val substitutor =
when (container) {
is ClassDescriptor -> {
actualClass = container
expectedClass = declaration.containingDeclaration as ClassDescriptor
// TODO: this might not work for members of inner generic classes
runIf(expectedClass.declaredTypeParameters.size == container.declaredTypeParameters.size) {
context.createExpectActualTypeParameterSubstitutor(
expectedClass.declaredTypeParameters,
container.declaredTypeParameters,
parentSubstitutor = null
)
}
}
else -> null
}
AbstractExpectActualCompatibilityChecker.getCallablesCompatibility(
expectDeclaration = declaration,
actualDeclaration = actual,
parentSubstitutor = substitutor,
expectContainingClass = expectedClass,
actualContainingClass = actualClass,
context
)
}
}
private fun matchActualClassAgainstPotentialExpects(
actual: ClassifierDescriptorWithTypeParameters,
candidates: Collection<ClassifierDescriptorWithTypeParameters>,
context: ClassicExpectActualMatchingContext,
): Map<ExpectActualCompatibility<MemberDescriptor>, List<ClassifierDescriptorWithTypeParameters>> {
return candidates.filter { declaration ->
actual != declaration && declaration is ClassDescriptor && declaration.isExpect
}.groupBy { expected ->
AbstractExpectActualCompatibilityChecker.getClassifiersCompatibility(
expected as ClassDescriptor,
actual,
context
)
}
}
private fun CallableMemberDescriptor.findNamesakesFromModule(
context: ClassicExpectActualMatchingContext,
module: ModuleDescriptor,