K2/MPP: treat Array<Some> & Array<out Some> as similar types in annotations
#KT-59561 Fixed Related to KT-61100
This commit is contained in:
committed by
Space Team
parent
f085d0f660
commit
9f6abfc166
+25
-1
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.symbols.resolvedAnnotationsWithArguments
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.mpp.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -305,10 +306,21 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
override fun areCompatibleExpectActualTypes(
|
||||
expectType: KotlinTypeMarker?,
|
||||
actualType: KotlinTypeMarker?,
|
||||
parameterOfAnnotationComparisonMode: Boolean,
|
||||
): Boolean {
|
||||
if (expectType == null) return actualType == null
|
||||
if (actualType == null) return false
|
||||
|
||||
if (parameterOfAnnotationComparisonMode && expectType is ConeClassLikeType && expectType.isArrayType &&
|
||||
actualType is ConeClassLikeType && actualType.isArrayType
|
||||
) {
|
||||
return AbstractTypeChecker.equalTypes(
|
||||
createTypeCheckerState(),
|
||||
expectType.convertToArrayWithOutProjections(),
|
||||
actualType.convertToArrayWithOutProjections()
|
||||
)
|
||||
}
|
||||
|
||||
return AbstractTypeChecker.equalTypes(
|
||||
createTypeCheckerState(),
|
||||
expectType,
|
||||
@@ -316,6 +328,15 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType.convertToArrayWithOutProjections(): ConeClassLikeType {
|
||||
val argumentsWithOutProjection = Array(typeArguments.size) { i ->
|
||||
val typeArgument = typeArguments[i]
|
||||
if (typeArgument !is ConeKotlinType) typeArgument
|
||||
else ConeKotlinTypeProjectionOut(typeArgument)
|
||||
}
|
||||
return ConeClassLikeTypeImpl(lookupTag, argumentsWithOutProjection, isNullable)
|
||||
}
|
||||
|
||||
override fun actualTypeIsSubtypeOfExpectType(expectType: KotlinTypeMarker, actualType: KotlinTypeMarker): Boolean {
|
||||
return AbstractTypeChecker.isSubtypeOf(
|
||||
createTypeCheckerState(),
|
||||
@@ -370,7 +391,10 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
check(annotation1.hasResolvedArguments() && annotation2.hasResolvedArguments()) {
|
||||
"By this time compared annotations are expected to have resolved arguments"
|
||||
}
|
||||
if (!areCompatibleExpectActualTypes(annotation1.resolvedType, annotation2.resolvedType)) {
|
||||
if (!areCompatibleExpectActualTypes(
|
||||
annotation1.resolvedType, annotation2.resolvedType, parameterOfAnnotationComparisonMode = false
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
val args1 = annotation1.argumentMapping.mapping
|
||||
|
||||
+25
-1
@@ -334,7 +334,11 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
override val TypeParameterSymbolMarker.isReified: Boolean
|
||||
get() = asIr().isReified
|
||||
|
||||
override fun areCompatibleExpectActualTypes(expectType: KotlinTypeMarker?, actualType: KotlinTypeMarker?): Boolean {
|
||||
override fun areCompatibleExpectActualTypes(
|
||||
expectType: KotlinTypeMarker?,
|
||||
actualType: KotlinTypeMarker?,
|
||||
parameterOfAnnotationComparisonMode: Boolean,
|
||||
): Boolean {
|
||||
if (expectType == null) return actualType == null
|
||||
if (actualType == null) return false
|
||||
/*
|
||||
@@ -355,6 +359,17 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
*/
|
||||
val actualizedExpectType = expectType.actualize()
|
||||
val actualizedActualType = actualType.actualize()
|
||||
|
||||
if (parameterOfAnnotationComparisonMode && actualizedExpectType is IrSimpleType && actualizedExpectType.isArray() &&
|
||||
actualizedActualType is IrSimpleType && actualizedActualType.isArray()
|
||||
) {
|
||||
return AbstractTypeChecker.equalTypes(
|
||||
createTypeCheckerState(),
|
||||
actualizedExpectType.convertToArrayWithOutProjections(),
|
||||
actualizedActualType.convertToArrayWithOutProjections()
|
||||
)
|
||||
}
|
||||
|
||||
return AbstractTypeChecker.equalTypes(
|
||||
createTypeCheckerState(),
|
||||
actualizedExpectType,
|
||||
@@ -362,6 +377,15 @@ internal abstract class IrExpectActualMatchingContext(
|
||||
)
|
||||
}
|
||||
|
||||
private fun IrSimpleType.convertToArrayWithOutProjections(): IrSimpleType {
|
||||
val argumentsWithOutProjection = List(arguments.size) { i ->
|
||||
val typeArgument = arguments[i]
|
||||
if (typeArgument !is IrSimpleType) typeArgument
|
||||
else makeTypeProjection(typeArgument, Variance.OUT_VARIANCE)
|
||||
}
|
||||
return IrSimpleTypeImpl(classifier, isNullable(), argumentsWithOutProjection, annotations)
|
||||
}
|
||||
|
||||
private fun createTypeCheckerState(): TypeCheckerState {
|
||||
return typeContext.newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = false)
|
||||
}
|
||||
|
||||
+21
-9
@@ -179,7 +179,7 @@ object AbstractExpectActualCompatibilityChecker {
|
||||
return expectSupertypes.all { expectSupertype ->
|
||||
val substitutedExpectType = substitutor.safeSubstitute(expectSupertype)
|
||||
actualSupertypes.any { actualSupertype ->
|
||||
areCompatibleExpectActualTypes(substitutedExpectType, actualSupertype)
|
||||
areCompatibleExpectActualTypes(substitutedExpectType, actualSupertype, parameterOfAnnotationComparisonMode = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,7 +321,8 @@ object AbstractExpectActualCompatibilityChecker {
|
||||
}
|
||||
|
||||
// We must prioritize to return STRONG incompatible over WEAK incompatible (because STRONG incompatibility allows to search for overloads)
|
||||
return getCallablesStrongIncompatibility(expectDeclaration, actualDeclaration, parentSubstitutor)
|
||||
val annotationMode = expectContainingClass?.classKind == ClassKind.ANNOTATION_CLASS
|
||||
return getCallablesStrongIncompatibility(expectDeclaration, actualDeclaration, annotationMode, parentSubstitutor)
|
||||
?: getCallablesWeakIncompatibility(expectDeclaration, actualDeclaration, expectContainingClass, actualContainingClass)
|
||||
?: ExpectActualCompatibility.Compatible
|
||||
}
|
||||
@@ -330,6 +331,7 @@ object AbstractExpectActualCompatibilityChecker {
|
||||
private fun getCallablesStrongIncompatibility(
|
||||
expectDeclaration: CallableSymbolMarker,
|
||||
actualDeclaration: CallableSymbolMarker,
|
||||
insideAnnotationClass: Boolean,
|
||||
parentSubstitutor: TypeSubstitutorMarker?,
|
||||
): Incompatible.StrongIncompatible<*>? {
|
||||
if (expectDeclaration is FunctionSymbolMarker != actualDeclaration is FunctionSymbolMarker) {
|
||||
@@ -363,18 +365,24 @@ object AbstractExpectActualCompatibilityChecker {
|
||||
if (
|
||||
!areCompatibleTypeLists(
|
||||
expectedValueParameters.toTypeList(substitutor),
|
||||
actualValueParameters.toTypeList(createEmptySubstitutor())
|
||||
) ||
|
||||
!areCompatibleExpectActualTypes(
|
||||
actualValueParameters.toTypeList(createEmptySubstitutor()),
|
||||
insideAnnotationClass
|
||||
) || !areCompatibleExpectActualTypes(
|
||||
expectedReceiverType?.let { substitutor.safeSubstitute(it) },
|
||||
actualReceiverType
|
||||
actualReceiverType,
|
||||
parameterOfAnnotationComparisonMode = false
|
||||
)
|
||||
) {
|
||||
return Incompatible.ParameterTypes
|
||||
}
|
||||
|
||||
if (shouldCheckReturnTypesOfCallables) {
|
||||
if (!areCompatibleExpectActualTypes(substitutor.safeSubstitute(expectDeclaration.returnType), actualDeclaration.returnType)) {
|
||||
if (!areCompatibleExpectActualTypes(
|
||||
substitutor.safeSubstitute(expectDeclaration.returnType),
|
||||
actualDeclaration.returnType,
|
||||
parameterOfAnnotationComparisonMode = insideAnnotationClass
|
||||
)
|
||||
) {
|
||||
return Incompatible.ReturnType
|
||||
}
|
||||
}
|
||||
@@ -492,9 +500,13 @@ object AbstractExpectActualCompatibilityChecker {
|
||||
private fun areCompatibleTypeLists(
|
||||
expectedTypes: List<KotlinTypeMarker?>,
|
||||
actualTypes: List<KotlinTypeMarker?>,
|
||||
insideAnnotationClass: Boolean,
|
||||
): Boolean {
|
||||
for (i in expectedTypes.indices) {
|
||||
if (!areCompatibleExpectActualTypes(expectedTypes[i], actualTypes[i])) {
|
||||
if (!areCompatibleExpectActualTypes(
|
||||
expectedTypes[i], actualTypes[i], parameterOfAnnotationComparisonMode = insideAnnotationClass
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -586,7 +598,7 @@ object AbstractExpectActualCompatibilityChecker {
|
||||
val actualBounds = actualTypeParameterSymbols[i].bounds
|
||||
if (
|
||||
expectBounds.size != actualBounds.size ||
|
||||
!areCompatibleTypeLists(expectBounds.map { substitutor.safeSubstitute(it) }, actualBounds)
|
||||
!areCompatibleTypeLists(expectBounds.map { substitutor.safeSubstitute(it) }, actualBounds, insideAnnotationClass = false)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
+1
@@ -145,6 +145,7 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
||||
fun areCompatibleExpectActualTypes(
|
||||
expectType: KotlinTypeMarker?,
|
||||
actualType: KotlinTypeMarker?,
|
||||
parameterOfAnnotationComparisonMode: Boolean = false,
|
||||
): Boolean
|
||||
|
||||
fun actualTypeIsSubtypeOfExpectType(
|
||||
|
||||
Vendored
+2
-2
@@ -7,7 +7,7 @@
|
||||
Throughput, AverageTime
|
||||
}<!>
|
||||
|
||||
<!INCOMPATIBLE_MATCHING{JVM}!>expect annotation class BenchmarkMode<!INCOMPATIBLE_MATCHING{JVM}!>(<!INCOMPATIBLE_MATCHING{JVM}!>vararg val value: Mode<!>)<!><!>
|
||||
expect annotation class BenchmarkMode(vararg val value: Mode)
|
||||
|
||||
// MODULE: m1-jvm()()(m1-common)
|
||||
// FILE: jvm.kt
|
||||
@@ -15,7 +15,7 @@
|
||||
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS("actual typealias Mode = Mode; expect constructor(): Mode")!>Mode<!> = mypackage.Mode
|
||||
|
||||
|
||||
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS("actual typealias BenchmarkMode = BenchmarkMode; expect constructor(vararg value: Array<out Mode>): BenchmarkMode The following declaration is incompatible because parameter types are different: constructor(vararg value: Array<Mode>): BenchmarkMode")!>BenchmarkMode<!> = mypackage.BenchmarkMode
|
||||
actual typealias BenchmarkMode = mypackage.BenchmarkMode
|
||||
|
||||
// FILE: mypackage/Mode.java
|
||||
|
||||
|
||||
Reference in New Issue
Block a user