[IR] 2/2 Propogate expect-actual checker incompatibilities to IR backend

Review: https://jetbrains.team/p/kt/reviews/12750/timeline
This commit is contained in:
Nikita Bobko
2023-10-17 12:47:10 +02:00
committed by teamcity
parent eb0c8c00c3
commit 8722e142f6
7 changed files with 61 additions and 27 deletions
@@ -467,7 +467,7 @@ class FirExpectActualMatchingContextImpl private constructor(
) )
} }
override fun onMismatchedOrIncompatibleMembersFromClassScope( override fun onMismatchedMembersFromClassScope(
expectSymbol: DeclarationSymbolMarker, expectSymbol: DeclarationSymbolMarker,
actualSymbolsByIncompatibility: Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker>>, actualSymbolsByIncompatibility: Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker>>,
containingExpectClassSymbol: RegularClassSymbolMarker?, containingExpectClassSymbol: RegularClassSymbolMarker?,
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.common.actualizer package org.jetbrains.kotlin.backend.common.actualizer
import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext import org.jetbrains.kotlin.KtDiagnosticReporterWithImplicitIrBasedContext
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.PsiIrFileEntry import org.jetbrains.kotlin.ir.PsiIrFileEntry
@@ -22,7 +23,9 @@ import org.jetbrains.kotlin.mpp.DeclarationSymbolMarker
import org.jetbrains.kotlin.mpp.RegularClassSymbolMarker import org.jetbrains.kotlin.mpp.RegularClassSymbolMarker
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualChecker
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualMatcher import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualMatcher
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCheckingCompatibility
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
import java.io.File import java.io.File
@@ -201,7 +204,7 @@ private class ExpectActualLinkCollector : IrElementVisitor<Unit, ExpectActualLin
} }
private fun matchExpectCallable(declaration: IrDeclarationWithName, callableId: CallableId, context: MatchingContext) { private fun matchExpectCallable(declaration: IrDeclarationWithName, callableId: CallableId, context: MatchingContext) {
matchExpectDeclaration( matchAndCheckExpectDeclaration(
declaration.symbol, declaration.symbol,
context.classActualizationInfo.actualTopLevels[callableId].orEmpty(), context.classActualizationInfo.actualTopLevels[callableId].orEmpty(),
context context
@@ -213,19 +216,27 @@ private class ExpectActualLinkCollector : IrElementVisitor<Unit, ExpectActualLin
val classId = declaration.classIdOrFail val classId = declaration.classIdOrFail
val expectClassSymbol = declaration.symbol val expectClassSymbol = declaration.symbol
val actualClassLikeSymbol = data.classActualizationInfo.getActualWithoutExpansion(classId) val actualClassLikeSymbol = data.classActualizationInfo.getActualWithoutExpansion(classId)
matchExpectDeclaration(expectClassSymbol, listOfNotNull(actualClassLikeSymbol), data) matchAndCheckExpectDeclaration(expectClassSymbol, listOfNotNull(actualClassLikeSymbol), data)
} }
private fun matchExpectDeclaration( private fun matchAndCheckExpectDeclaration(
expectSymbol: IrSymbol, expectSymbol: IrSymbol,
actualSymbols: List<IrSymbol>, actualSymbols: List<IrSymbol>,
context: MatchingContext context: MatchingContext
) { ) {
AbstractExpectActualMatcher.matchSingleExpectTopLevelDeclarationAgainstPotentialActuals( val matched = AbstractExpectActualMatcher.matchSingleExpectTopLevelDeclarationAgainstPotentialActuals(
expectSymbol, expectSymbol,
actualSymbols, actualSymbols,
context, context,
) )
if (matched != null) {
AbstractExpectActualChecker.checkSingleExpectTopLevelDeclarationAgainstPotentialActuals(
expectSymbol,
listOf(matched),
context,
checkClassScopesCompatibility = true,
)
}
} }
override fun visitElement(element: IrElement, data: MatchingContext) { override fun visitElement(element: IrElement, data: MatchingContext) {
@@ -259,7 +270,22 @@ private class ExpectActualLinkCollector : IrElementVisitor<Unit, ExpectActualLin
recordActualForExpectDeclaration(expectSymbol, actualSymbol, destination) recordActualForExpectDeclaration(expectSymbol, actualSymbol, destination)
} }
override fun onMismatchedOrIncompatibleMembersFromClassScope( override fun onIncompatibleMembersFromClassScope(
expectSymbol: DeclarationSymbolMarker,
actualSymbolsByIncompatibility: Map<ExpectActualCheckingCompatibility.Incompatible<*>, List<DeclarationSymbolMarker>>,
containingExpectClassSymbol: RegularClassSymbolMarker?,
containingActualClassSymbol: RegularClassSymbolMarker?
) {
require(expectSymbol is IrSymbol)
for ((incompatibility, actualMemberSymbols) in actualSymbolsByIncompatibility) {
for (actualSymbol in actualMemberSymbols) {
require(actualSymbol is IrSymbol)
diagnosticsReporter.reportIncompatibleExpectActual(expectSymbol, actualSymbol, incompatibility)
}
}
}
override fun onMismatchedMembersFromClassScope(
expectSymbol: DeclarationSymbolMarker, expectSymbol: DeclarationSymbolMarker,
actualSymbolsByIncompatibility: Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker>>, actualSymbolsByIncompatibility: Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker>>,
containingExpectClassSymbol: RegularClassSymbolMarker?, containingExpectClassSymbol: RegularClassSymbolMarker?,
@@ -318,8 +318,7 @@ object AbstractExpectActualChecker {
} }
incompatibleMembers?.add(expectMember to incompatibilityMap) incompatibleMembers?.add(expectMember to incompatibilityMap)
// Temporarily comment out reporting checking incompatibilities to backend. KT-62590 is in progress onIncompatibleMembersFromClassScope(expectMember, incompatibilityMap, expectClassSymbol, actualClassSymbol)
//onMismatchedOrIncompatibleMembersFromClassScope(expectMember, incompatibilityMap, expectClassSymbol, actualClassSymbol)
} }
context(ExpectActualMatchingContext<*>) context(ExpectActualMatchingContext<*>)
@@ -9,6 +9,8 @@ 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.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.ExpectActualCompatibility
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
@@ -50,17 +52,15 @@ object AbstractExpectActualMatcher {
expectDeclaration: DeclarationSymbolMarker, expectDeclaration: DeclarationSymbolMarker,
actualDeclarations: List<DeclarationSymbolMarker>, actualDeclarations: List<DeclarationSymbolMarker>,
context: ExpectActualMatchingContext<T>, context: ExpectActualMatchingContext<T>,
) { ): DeclarationSymbolMarker? = with(context) {
with(context) { matchSingleExpectAgainstPotentialActuals(
matchSingleExpectAgainstPotentialActuals( expectDeclaration,
expectDeclaration, actualDeclarations,
actualDeclarations, substitutor = null,
substitutor = null, expectClassSymbol = null,
expectClassSymbol = null, actualClassSymbol = null,
actualClassSymbol = null, mismatchedMembers = null,
unfulfilled = null, )
)
}
} }
fun matchClassifiers( fun matchClassifiers(
@@ -100,7 +100,7 @@ object AbstractExpectActualMatcher {
substitutor, substitutor,
expectClassSymbol, expectClassSymbol,
actualClassSymbol, actualClassSymbol,
unfulfilled = null, mismatchedMembers = null,
) )
} }
@@ -121,7 +121,7 @@ object AbstractExpectActualMatcher {
substitutor: TypeSubstitutorMarker?, substitutor: TypeSubstitutorMarker?,
expectClassSymbol: RegularClassSymbolMarker?, expectClassSymbol: RegularClassSymbolMarker?,
actualClassSymbol: RegularClassSymbolMarker?, actualClassSymbol: RegularClassSymbolMarker?,
unfulfilled: MutableList<Pair<DeclarationSymbolMarker, Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker?>>>>?, mismatchedMembers: MutableList<Pair<DeclarationSymbolMarker, Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker?>>>>?,
): DeclarationSymbolMarker? { ): DeclarationSymbolMarker? {
val mapping = actualMembers.keysToMap { actualMember -> val mapping = actualMembers.keysToMap { actualMember ->
when (expectMember) { when (expectMember) {
@@ -152,8 +152,8 @@ object AbstractExpectActualMatcher {
} }
} }
unfulfilled?.add(expectMember to incompatibilityMap) mismatchedMembers?.add(expectMember to incompatibilityMap)
onMismatchedOrIncompatibleMembersFromClassScope(expectMember, incompatibilityMap, expectClassSymbol, actualClassSymbol) onMismatchedMembersFromClassScope(expectMember, incompatibilityMap, expectClassSymbol, actualClassSymbol)
return null return null
} }
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.mpp.*
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
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.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.model.KotlinTypeMarker import org.jetbrains.kotlin.types.model.KotlinTypeMarker
@@ -172,7 +173,14 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
containingActualClassSymbol: RegularClassSymbolMarker?, containingActualClassSymbol: RegularClassSymbolMarker?,
) {} ) {}
fun onMismatchedOrIncompatibleMembersFromClassScope( fun onIncompatibleMembersFromClassScope(
expectSymbol: DeclarationSymbolMarker,
actualSymbolsByIncompatibility: Map<ExpectActualCheckingCompatibility.Incompatible<*>, List<DeclarationSymbolMarker>>,
containingExpectClassSymbol: RegularClassSymbolMarker?,
containingActualClassSymbol: RegularClassSymbolMarker?,
) {}
fun onMismatchedMembersFromClassScope(
expectSymbol: DeclarationSymbolMarker, expectSymbol: DeclarationSymbolMarker,
actualSymbolsByIncompatibility: Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker>>, actualSymbolsByIncompatibility: Map<ExpectActualMatchingCompatibility.Mismatch, List<DeclarationSymbolMarker>>,
containingExpectClassSymbol: RegularClassSymbolMarker?, containingExpectClassSymbol: RegularClassSymbolMarker?,
@@ -2,7 +2,7 @@
// FILE: common.kt // FILE: common.kt
interface A interface A
<!INCOMPATIBLE_MATCHING{JVM}, INCOMPATIBLE_MATCHING{JVM}!>expect fun <T : A> foo(t: T): String<!> <!INCOMPATIBLE_MATCHING{JVM}!>expect fun <T : A> foo(t: T): String<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve.multiplatform
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility.Mismatch import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility.Mismatch
private const val TYPE_PARAMETER_COUNT = "number of type parameters is different" private const val TYPE_PARAMETER_COUNT = "number of type parameters is different"
private const val TYPE_PARAMETER_UPPER_BOUNDS = "upper bounds of type parameters are different"
// Note that the reason is used in the diagnostic output, see PlatformIncompatibilityDiagnosticRenderer // Note that the reason is used in the diagnostic output, see PlatformIncompatibilityDiagnosticRenderer
/** /**
@@ -37,7 +38,7 @@ sealed class ExpectActualMatchingCompatibility : ExpectActualCompatibility<Nothi
object ParameterCount : Mismatch("number of value parameters is different") object ParameterCount : Mismatch("number of value parameters is different")
object FunctionTypeParameterCount : Mismatch(TYPE_PARAMETER_COUNT) object FunctionTypeParameterCount : Mismatch(TYPE_PARAMETER_COUNT)
object ParameterTypes : Mismatch("parameter types are different") object ParameterTypes : Mismatch("parameter types are different")
object FunctionTypeParameterUpperBounds : Mismatch("upper bounds of type parameters are different") object FunctionTypeParameterUpperBounds : Mismatch(TYPE_PARAMETER_UPPER_BOUNDS)
object MatchedSuccessfully : ExpectActualMatchingCompatibility() object MatchedSuccessfully : ExpectActualMatchingCompatibility()
} }
@@ -90,7 +91,7 @@ sealed class ExpectActualCheckingCompatibility<out D> : ExpectActualCompatibilit
object Modality : Incompatible<Nothing>("modality is different") object Modality : Incompatible<Nothing>("modality is different")
object Visibility : Incompatible<Nothing>("visibility is different") object Visibility : Incompatible<Nothing>("visibility is different")
object ClassTypeParameterUpperBounds : Incompatible<Nothing>(ExpectActualMatchingCompatibility.FunctionTypeParameterUpperBounds.reason) object ClassTypeParameterUpperBounds : Incompatible<Nothing>(TYPE_PARAMETER_UPPER_BOUNDS)
object TypeParameterVariance : Incompatible<Nothing>("declaration-site variances of type parameters are different") object TypeParameterVariance : Incompatible<Nothing>("declaration-site variances of type parameters are different")
object TypeParameterReified : Incompatible<Nothing>("some type parameter is reified in one declaration and non-reified in the other") object TypeParameterReified : Incompatible<Nothing>("some type parameter is reified in one declaration and non-reified in the other")
object Compatible : ExpectActualCheckingCompatibility<Nothing>() object Compatible : ExpectActualCheckingCompatibility<Nothing>()