[FIR, IR] Cleanup: deduplicate common code in AbstractExpectActualMatcher & AbstractExpectActualChecker
Review: https://jetbrains.team/p/kt/reviews/12750/timeline
This commit is contained in:
+3
-70
@@ -10,11 +10,9 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
import org.jetbrains.kotlin.mpp.*
|
import org.jetbrains.kotlin.mpp.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCheckingCompatibility
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCheckingCompatibility
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
|
||||||
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
import org.jetbrains.kotlin.utils.SmartList
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.enumMapOf
|
import org.jetbrains.kotlin.utils.addToStdlib.enumMapOf
|
||||||
@@ -225,10 +223,7 @@ object AbstractExpectActualChecker {
|
|||||||
outer@ for (expectMember in expectClassSymbol.collectAllMembers(isActualDeclaration = false)) {
|
outer@ for (expectMember in expectClassSymbol.collectAllMembers(isActualDeclaration = false)) {
|
||||||
if (expectMember is CallableSymbolMarker && expectMember.shouldSkipMatching(expectClassSymbol)) continue
|
if (expectMember is CallableSymbolMarker && expectMember.shouldSkipMatching(expectClassSymbol)) continue
|
||||||
|
|
||||||
val actualMembers = actualMembersByName[expectMember.name]?.filter { actualMember ->
|
val actualMembers = getPossibleActualsByExpectName(expectMember, actualMembersByName)
|
||||||
expectMember is CallableSymbolMarker && actualMember is CallableSymbolMarker ||
|
|
||||||
expectMember is RegularClassSymbolMarker && actualMember is RegularClassSymbolMarker
|
|
||||||
}.orEmpty()
|
|
||||||
|
|
||||||
val matched = AbstractExpectActualMatcher.matchSingleExpectAgainstPotentialActuals(
|
val matched = AbstractExpectActualMatcher.matchSingleExpectAgainstPotentialActuals(
|
||||||
expectMember,
|
expectMember,
|
||||||
@@ -317,22 +312,9 @@ object AbstractExpectActualChecker {
|
|||||||
expectContainingClass: RegularClassSymbolMarker?,
|
expectContainingClass: RegularClassSymbolMarker?,
|
||||||
actualContainingClass: RegularClassSymbolMarker?,
|
actualContainingClass: RegularClassSymbolMarker?,
|
||||||
): ExpectActualCheckingCompatibility<*> {
|
): ExpectActualCheckingCompatibility<*> {
|
||||||
require(
|
checkCallablesInvariants(expectDeclaration, actualDeclaration)
|
||||||
(expectDeclaration is ConstructorSymbolMarker && actualDeclaration is ConstructorSymbolMarker) ||
|
|
||||||
expectDeclaration.callableId.callableName == actualDeclaration.callableId.callableName
|
|
||||||
) {
|
|
||||||
"This function should be invoked only for declarations with the same name: $expectDeclaration, $actualDeclaration"
|
|
||||||
}
|
|
||||||
require((expectDeclaration.dispatchReceiverType == null) == (actualDeclaration.dispatchReceiverType == null)) {
|
|
||||||
"This function should be invoked only for declarations in the same kind of container (both members or both top level): $expectDeclaration, $actualDeclaration"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (areEnumConstructors(expectDeclaration, actualDeclaration, expectContainingClass, actualContainingClass)) {
|
||||||
expectContainingClass?.classKind == ClassKind.ENUM_CLASS &&
|
|
||||||
actualContainingClass?.classKind == ClassKind.ENUM_CLASS &&
|
|
||||||
expectDeclaration is ConstructorSymbolMarker &&
|
|
||||||
actualDeclaration is ConstructorSymbolMarker
|
|
||||||
) {
|
|
||||||
return ExpectActualCheckingCompatibility.Compatible
|
return ExpectActualCheckingCompatibility.Compatible
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,23 +433,6 @@ object AbstractExpectActualChecker {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
|
||||||
private fun areCompatibleTypeLists(
|
|
||||||
expectedTypes: List<KotlinTypeMarker?>,
|
|
||||||
actualTypes: List<KotlinTypeMarker?>,
|
|
||||||
insideAnnotationClass: Boolean,
|
|
||||||
): Boolean {
|
|
||||||
for (i in expectedTypes.indices) {
|
|
||||||
if (!areCompatibleExpectActualTypes(
|
|
||||||
expectedTypes[i], actualTypes[i], parameterOfAnnotationComparisonMode = insideAnnotationClass
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
context(ExpectActualMatchingContext<*>)
|
||||||
private fun areCompatibleClassKinds(
|
private fun areCompatibleClassKinds(
|
||||||
expectClass: RegularClassSymbolMarker,
|
expectClass: RegularClassSymbolMarker,
|
||||||
@@ -542,26 +507,6 @@ object AbstractExpectActualChecker {
|
|||||||
return result != null && result > 0
|
return result != null && result > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
|
||||||
private fun areCompatibleTypeParameterUpperBounds(
|
|
||||||
expectTypeParameterSymbols: List<TypeParameterSymbolMarker>,
|
|
||||||
actualTypeParameterSymbols: List<TypeParameterSymbolMarker>,
|
|
||||||
substitutor: TypeSubstitutorMarker,
|
|
||||||
): Boolean {
|
|
||||||
for (i in expectTypeParameterSymbols.indices) {
|
|
||||||
val expectBounds = expectTypeParameterSymbols[i].bounds
|
|
||||||
val actualBounds = actualTypeParameterSymbols[i].bounds
|
|
||||||
if (
|
|
||||||
expectBounds.size != actualBounds.size ||
|
|
||||||
!areCompatibleTypeLists(expectBounds.map { substitutor.safeSubstitute(it) }, actualBounds, insideAnnotationClass = false)
|
|
||||||
) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
context(ExpectActualMatchingContext<*>)
|
||||||
private fun getTypeParametersVarianceOrReifiedIncompatibility(
|
private fun getTypeParametersVarianceOrReifiedIncompatibility(
|
||||||
expectTypeParameterSymbols: List<TypeParameterSymbolMarker>,
|
expectTypeParameterSymbols: List<TypeParameterSymbolMarker>,
|
||||||
@@ -645,18 +590,6 @@ object AbstractExpectActualChecker {
|
|||||||
private inline fun <T, K> equalBy(first: T, second: T, selector: (T) -> K): Boolean =
|
private inline fun <T, K> equalBy(first: T, second: T, selector: (T) -> K): Boolean =
|
||||||
selector(first) == selector(second)
|
selector(first) == selector(second)
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
|
||||||
private val DeclarationSymbolMarker.name: Name
|
|
||||||
get() = when (this) {
|
|
||||||
is ConstructorSymbolMarker -> SpecialNames.INIT
|
|
||||||
is ValueParameterSymbolMarker -> parameterName
|
|
||||||
is CallableSymbolMarker -> callableId.callableName
|
|
||||||
is RegularClassSymbolMarker -> classId.shortClassName
|
|
||||||
is TypeAliasSymbolMarker -> classId.shortClassName
|
|
||||||
is TypeParameterSymbolMarker -> parameterName
|
|
||||||
else -> error("Unsupported declaration: $this")
|
|
||||||
}
|
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
context(ExpectActualMatchingContext<*>)
|
||||||
private val RegularClassSymbolMarker.isCtorless: Boolean
|
private val RegularClassSymbolMarker.isCtorless: Boolean
|
||||||
get() = getMembersForExpectClass(SpecialNames.INIT).isEmpty()
|
get() = getMembersForExpectClass(SpecialNames.INIT).isEmpty()
|
||||||
|
|||||||
+3
-70
@@ -7,8 +7,6 @@ package org.jetbrains.kotlin.resolve.calls.mpp
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.mpp.*
|
import org.jetbrains.kotlin.mpp.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||||
@@ -93,10 +91,7 @@ object AbstractExpectActualMatcher {
|
|||||||
outer@ for (expectMember in expectClassSymbol.collectAllMembers(isActualDeclaration = false)) {
|
outer@ for (expectMember in expectClassSymbol.collectAllMembers(isActualDeclaration = false)) {
|
||||||
if (expectMember is CallableSymbolMarker && expectMember.shouldSkipMatching(expectClassSymbol)) continue
|
if (expectMember is CallableSymbolMarker && expectMember.shouldSkipMatching(expectClassSymbol)) continue
|
||||||
|
|
||||||
val actualMembers = actualMembersByName[expectMember.name]?.filter { actualMember ->
|
val actualMembers = getPossibleActualsByExpectName(expectMember, actualMembersByName)
|
||||||
expectMember is CallableSymbolMarker && actualMember is CallableSymbolMarker ||
|
|
||||||
expectMember is RegularClassSymbolMarker && actualMember is RegularClassSymbolMarker
|
|
||||||
}.orEmpty()
|
|
||||||
|
|
||||||
matchSingleExpectAgainstPotentialActuals(
|
matchSingleExpectAgainstPotentialActuals(
|
||||||
expectMember,
|
expectMember,
|
||||||
@@ -169,22 +164,9 @@ object AbstractExpectActualMatcher {
|
|||||||
expectContainingClass: RegularClassSymbolMarker?,
|
expectContainingClass: RegularClassSymbolMarker?,
|
||||||
actualContainingClass: RegularClassSymbolMarker?,
|
actualContainingClass: RegularClassSymbolMarker?,
|
||||||
): ExpectActualMatchingCompatibility {
|
): ExpectActualMatchingCompatibility {
|
||||||
require(
|
checkCallablesInvariants(expectDeclaration, actualDeclaration)
|
||||||
(expectDeclaration is ConstructorSymbolMarker && actualDeclaration is ConstructorSymbolMarker) ||
|
|
||||||
expectDeclaration.callableId.callableName == actualDeclaration.callableId.callableName
|
|
||||||
) {
|
|
||||||
"This function should be invoked only for declarations with the same name: $expectDeclaration, $actualDeclaration"
|
|
||||||
}
|
|
||||||
require((expectDeclaration.dispatchReceiverType == null) == (actualDeclaration.dispatchReceiverType == null)) {
|
|
||||||
"This function should be invoked only for declarations in the same kind of container (both members or both top level): $expectDeclaration, $actualDeclaration"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (areEnumConstructors(expectDeclaration, actualDeclaration, expectContainingClass, actualContainingClass)) {
|
||||||
expectContainingClass?.classKind == ClassKind.ENUM_CLASS &&
|
|
||||||
actualContainingClass?.classKind == ClassKind.ENUM_CLASS &&
|
|
||||||
expectDeclaration is ConstructorSymbolMarker &&
|
|
||||||
actualDeclaration is ConstructorSymbolMarker
|
|
||||||
) {
|
|
||||||
return ExpectActualMatchingCompatibility.MatchedSuccessfully
|
return ExpectActualMatchingCompatibility.MatchedSuccessfully
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,57 +247,8 @@ object AbstractExpectActualMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
|
||||||
private fun areCompatibleTypeLists(
|
|
||||||
expectedTypes: List<KotlinTypeMarker?>,
|
|
||||||
actualTypes: List<KotlinTypeMarker?>,
|
|
||||||
insideAnnotationClass: Boolean,
|
|
||||||
): Boolean {
|
|
||||||
for (i in expectedTypes.indices) {
|
|
||||||
if (!areCompatibleExpectActualTypes(
|
|
||||||
expectedTypes[i], actualTypes[i], parameterOfAnnotationComparisonMode = insideAnnotationClass
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
|
||||||
private fun areCompatibleTypeParameterUpperBounds(
|
|
||||||
expectTypeParameterSymbols: List<TypeParameterSymbolMarker>,
|
|
||||||
actualTypeParameterSymbols: List<TypeParameterSymbolMarker>,
|
|
||||||
substitutor: TypeSubstitutorMarker,
|
|
||||||
): Boolean {
|
|
||||||
for (i in expectTypeParameterSymbols.indices) {
|
|
||||||
val expectBounds = expectTypeParameterSymbols[i].bounds
|
|
||||||
val actualBounds = actualTypeParameterSymbols[i].bounds
|
|
||||||
if (
|
|
||||||
expectBounds.size != actualBounds.size ||
|
|
||||||
!areCompatibleTypeLists(expectBounds.map { substitutor.safeSubstitute(it) }, actualBounds, insideAnnotationClass = false)
|
|
||||||
) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------- Utils ----------------------------------------
|
// ---------------------------------------- Utils ----------------------------------------
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
|
||||||
private val DeclarationSymbolMarker.name: Name
|
|
||||||
get() = when (this) {
|
|
||||||
is ConstructorSymbolMarker -> SpecialNames.INIT
|
|
||||||
is ValueParameterSymbolMarker -> parameterName
|
|
||||||
is CallableSymbolMarker -> callableId.callableName
|
|
||||||
is RegularClassSymbolMarker -> classId.shortClassName
|
|
||||||
is TypeAliasSymbolMarker -> classId.shortClassName
|
|
||||||
is TypeParameterSymbolMarker -> parameterName
|
|
||||||
else -> error("Unsupported declaration: $this")
|
|
||||||
}
|
|
||||||
|
|
||||||
context(ExpectActualMatchingContext<*>)
|
context(ExpectActualMatchingContext<*>)
|
||||||
private fun List<ValueParameterSymbolMarker>.toTypeList(substitutor: TypeSubstitutorMarker): List<KotlinTypeMarker> {
|
private fun List<ValueParameterSymbolMarker>.toTypeList(substitutor: TypeSubstitutorMarker): List<KotlinTypeMarker> {
|
||||||
return this.map { substitutor.safeSubstitute(it.returnType) }
|
return this.map { substitutor.safeSubstitute(it.returnType) }
|
||||||
|
|||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.mpp
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.mpp.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
|
import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
||||||
|
|
||||||
|
context(ExpectActualMatchingContext<*>)
|
||||||
|
internal fun getPossibleActualsByExpectName(
|
||||||
|
expectMember: DeclarationSymbolMarker,
|
||||||
|
actualMembersByName: Map<Name, List<DeclarationSymbolMarker>>,
|
||||||
|
): List<DeclarationSymbolMarker> {
|
||||||
|
val actualMembers = actualMembersByName[expectMember.name]?.filter { actualMember ->
|
||||||
|
expectMember is CallableSymbolMarker && actualMember is CallableSymbolMarker ||
|
||||||
|
expectMember is RegularClassSymbolMarker && actualMember is RegularClassSymbolMarker
|
||||||
|
}.orEmpty()
|
||||||
|
return actualMembers
|
||||||
|
}
|
||||||
|
|
||||||
|
context(ExpectActualMatchingContext<*>)
|
||||||
|
internal val DeclarationSymbolMarker.name: Name
|
||||||
|
get() = when (this) {
|
||||||
|
is ConstructorSymbolMarker -> SpecialNames.INIT
|
||||||
|
is ValueParameterSymbolMarker -> parameterName
|
||||||
|
is CallableSymbolMarker -> callableId.callableName
|
||||||
|
is RegularClassSymbolMarker -> classId.shortClassName
|
||||||
|
is TypeAliasSymbolMarker -> classId.shortClassName
|
||||||
|
is TypeParameterSymbolMarker -> parameterName
|
||||||
|
else -> error("Unsupported declaration: $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
context(ExpectActualMatchingContext<*>)
|
||||||
|
internal fun areCompatibleTypeParameterUpperBounds(
|
||||||
|
expectTypeParameterSymbols: List<TypeParameterSymbolMarker>,
|
||||||
|
actualTypeParameterSymbols: List<TypeParameterSymbolMarker>,
|
||||||
|
substitutor: TypeSubstitutorMarker,
|
||||||
|
): Boolean {
|
||||||
|
for (i in expectTypeParameterSymbols.indices) {
|
||||||
|
val expectBounds = expectTypeParameterSymbols[i].bounds
|
||||||
|
val actualBounds = actualTypeParameterSymbols[i].bounds
|
||||||
|
if (
|
||||||
|
expectBounds.size != actualBounds.size ||
|
||||||
|
!areCompatibleTypeLists(
|
||||||
|
expectBounds.map { substitutor.safeSubstitute(it) },
|
||||||
|
actualBounds,
|
||||||
|
insideAnnotationClass = false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
context(ExpectActualMatchingContext<*>)
|
||||||
|
internal fun areCompatibleTypeLists(
|
||||||
|
expectedTypes: List<KotlinTypeMarker?>,
|
||||||
|
actualTypes: List<KotlinTypeMarker?>,
|
||||||
|
insideAnnotationClass: Boolean,
|
||||||
|
): Boolean {
|
||||||
|
for (i in expectedTypes.indices) {
|
||||||
|
if (!areCompatibleExpectActualTypes(
|
||||||
|
expectedTypes[i], actualTypes[i], parameterOfAnnotationComparisonMode = insideAnnotationClass
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In terms of KMP, there is no such thing as `expect constructor` for enums,
|
||||||
|
* but they are physically exist in FIR and IR, so we need to skip matching and checking for them
|
||||||
|
*/
|
||||||
|
context(ExpectActualMatchingContext<*>)
|
||||||
|
internal fun areEnumConstructors(
|
||||||
|
expectDeclaration: CallableSymbolMarker,
|
||||||
|
actualDeclaration: CallableSymbolMarker,
|
||||||
|
expectContainingClass: RegularClassSymbolMarker?,
|
||||||
|
actualContainingClass: RegularClassSymbolMarker?,
|
||||||
|
): Boolean = expectContainingClass?.classKind == ClassKind.ENUM_CLASS &&
|
||||||
|
actualContainingClass?.classKind == ClassKind.ENUM_CLASS &&
|
||||||
|
expectDeclaration is ConstructorSymbolMarker &&
|
||||||
|
actualDeclaration is ConstructorSymbolMarker
|
||||||
|
|
||||||
|
context(ExpectActualMatchingContext<*>)
|
||||||
|
internal fun checkCallablesInvariants(
|
||||||
|
expectDeclaration: CallableSymbolMarker,
|
||||||
|
actualDeclaration: CallableSymbolMarker,
|
||||||
|
) {
|
||||||
|
require(
|
||||||
|
(expectDeclaration is ConstructorSymbolMarker && actualDeclaration is ConstructorSymbolMarker) ||
|
||||||
|
expectDeclaration.callableId.callableName == actualDeclaration.callableId.callableName
|
||||||
|
) {
|
||||||
|
"This function should be invoked only for declarations with the same name: $expectDeclaration, $actualDeclaration"
|
||||||
|
}
|
||||||
|
require((expectDeclaration.dispatchReceiverType == null) == (actualDeclaration.dispatchReceiverType == null)) {
|
||||||
|
"This function should be invoked only for declarations in the same kind of container (both members or both top level): $expectDeclaration, $actualDeclaration"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user