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.impl.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.resolvedAnnotationsWithArguments
|
import org.jetbrains.kotlin.fir.symbols.resolvedAnnotationsWithArguments
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
import org.jetbrains.kotlin.mpp.*
|
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
|
||||||
@@ -305,10 +306,21 @@ class FirExpectActualMatchingContextImpl private constructor(
|
|||||||
override fun areCompatibleExpectActualTypes(
|
override fun areCompatibleExpectActualTypes(
|
||||||
expectType: KotlinTypeMarker?,
|
expectType: KotlinTypeMarker?,
|
||||||
actualType: KotlinTypeMarker?,
|
actualType: KotlinTypeMarker?,
|
||||||
|
parameterOfAnnotationComparisonMode: Boolean,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (expectType == null) return actualType == null
|
if (expectType == null) return actualType == null
|
||||||
if (actualType == null) return false
|
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(
|
return AbstractTypeChecker.equalTypes(
|
||||||
createTypeCheckerState(),
|
createTypeCheckerState(),
|
||||||
expectType,
|
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 {
|
override fun actualTypeIsSubtypeOfExpectType(expectType: KotlinTypeMarker, actualType: KotlinTypeMarker): Boolean {
|
||||||
return AbstractTypeChecker.isSubtypeOf(
|
return AbstractTypeChecker.isSubtypeOf(
|
||||||
createTypeCheckerState(),
|
createTypeCheckerState(),
|
||||||
@@ -370,7 +391,10 @@ class FirExpectActualMatchingContextImpl private constructor(
|
|||||||
check(annotation1.hasResolvedArguments() && annotation2.hasResolvedArguments()) {
|
check(annotation1.hasResolvedArguments() && annotation2.hasResolvedArguments()) {
|
||||||
"By this time compared annotations are expected to have resolved arguments"
|
"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
|
return false
|
||||||
}
|
}
|
||||||
val args1 = annotation1.argumentMapping.mapping
|
val args1 = annotation1.argumentMapping.mapping
|
||||||
|
|||||||
+25
-1
@@ -334,7 +334,11 @@ internal abstract class IrExpectActualMatchingContext(
|
|||||||
override val TypeParameterSymbolMarker.isReified: Boolean
|
override val TypeParameterSymbolMarker.isReified: Boolean
|
||||||
get() = asIr().isReified
|
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 (expectType == null) return actualType == null
|
||||||
if (actualType == null) return false
|
if (actualType == null) return false
|
||||||
/*
|
/*
|
||||||
@@ -355,6 +359,17 @@ internal abstract class IrExpectActualMatchingContext(
|
|||||||
*/
|
*/
|
||||||
val actualizedExpectType = expectType.actualize()
|
val actualizedExpectType = expectType.actualize()
|
||||||
val actualizedActualType = actualType.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(
|
return AbstractTypeChecker.equalTypes(
|
||||||
createTypeCheckerState(),
|
createTypeCheckerState(),
|
||||||
actualizedExpectType,
|
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 {
|
private fun createTypeCheckerState(): TypeCheckerState {
|
||||||
return typeContext.newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = false)
|
return typeContext.newTypeCheckerState(errorTypesEqualToAnything = true, stubTypesEqualToAnything = false)
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-9
@@ -179,7 +179,7 @@ object AbstractExpectActualCompatibilityChecker {
|
|||||||
return expectSupertypes.all { expectSupertype ->
|
return expectSupertypes.all { expectSupertype ->
|
||||||
val substitutedExpectType = substitutor.safeSubstitute(expectSupertype)
|
val substitutedExpectType = substitutor.safeSubstitute(expectSupertype)
|
||||||
actualSupertypes.any { actualSupertype ->
|
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)
|
// 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)
|
?: getCallablesWeakIncompatibility(expectDeclaration, actualDeclaration, expectContainingClass, actualContainingClass)
|
||||||
?: ExpectActualCompatibility.Compatible
|
?: ExpectActualCompatibility.Compatible
|
||||||
}
|
}
|
||||||
@@ -330,6 +331,7 @@ object AbstractExpectActualCompatibilityChecker {
|
|||||||
private fun getCallablesStrongIncompatibility(
|
private fun getCallablesStrongIncompatibility(
|
||||||
expectDeclaration: CallableSymbolMarker,
|
expectDeclaration: CallableSymbolMarker,
|
||||||
actualDeclaration: CallableSymbolMarker,
|
actualDeclaration: CallableSymbolMarker,
|
||||||
|
insideAnnotationClass: Boolean,
|
||||||
parentSubstitutor: TypeSubstitutorMarker?,
|
parentSubstitutor: TypeSubstitutorMarker?,
|
||||||
): Incompatible.StrongIncompatible<*>? {
|
): Incompatible.StrongIncompatible<*>? {
|
||||||
if (expectDeclaration is FunctionSymbolMarker != actualDeclaration is FunctionSymbolMarker) {
|
if (expectDeclaration is FunctionSymbolMarker != actualDeclaration is FunctionSymbolMarker) {
|
||||||
@@ -363,18 +365,24 @@ object AbstractExpectActualCompatibilityChecker {
|
|||||||
if (
|
if (
|
||||||
!areCompatibleTypeLists(
|
!areCompatibleTypeLists(
|
||||||
expectedValueParameters.toTypeList(substitutor),
|
expectedValueParameters.toTypeList(substitutor),
|
||||||
actualValueParameters.toTypeList(createEmptySubstitutor())
|
actualValueParameters.toTypeList(createEmptySubstitutor()),
|
||||||
) ||
|
insideAnnotationClass
|
||||||
!areCompatibleExpectActualTypes(
|
) || !areCompatibleExpectActualTypes(
|
||||||
expectedReceiverType?.let { substitutor.safeSubstitute(it) },
|
expectedReceiverType?.let { substitutor.safeSubstitute(it) },
|
||||||
actualReceiverType
|
actualReceiverType,
|
||||||
|
parameterOfAnnotationComparisonMode = false
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return Incompatible.ParameterTypes
|
return Incompatible.ParameterTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldCheckReturnTypesOfCallables) {
|
if (shouldCheckReturnTypesOfCallables) {
|
||||||
if (!areCompatibleExpectActualTypes(substitutor.safeSubstitute(expectDeclaration.returnType), actualDeclaration.returnType)) {
|
if (!areCompatibleExpectActualTypes(
|
||||||
|
substitutor.safeSubstitute(expectDeclaration.returnType),
|
||||||
|
actualDeclaration.returnType,
|
||||||
|
parameterOfAnnotationComparisonMode = insideAnnotationClass
|
||||||
|
)
|
||||||
|
) {
|
||||||
return Incompatible.ReturnType
|
return Incompatible.ReturnType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -492,9 +500,13 @@ object AbstractExpectActualCompatibilityChecker {
|
|||||||
private fun areCompatibleTypeLists(
|
private fun areCompatibleTypeLists(
|
||||||
expectedTypes: List<KotlinTypeMarker?>,
|
expectedTypes: List<KotlinTypeMarker?>,
|
||||||
actualTypes: List<KotlinTypeMarker?>,
|
actualTypes: List<KotlinTypeMarker?>,
|
||||||
|
insideAnnotationClass: Boolean,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
for (i in expectedTypes.indices) {
|
for (i in expectedTypes.indices) {
|
||||||
if (!areCompatibleExpectActualTypes(expectedTypes[i], actualTypes[i])) {
|
if (!areCompatibleExpectActualTypes(
|
||||||
|
expectedTypes[i], actualTypes[i], parameterOfAnnotationComparisonMode = insideAnnotationClass
|
||||||
|
)
|
||||||
|
) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -586,7 +598,7 @@ object AbstractExpectActualCompatibilityChecker {
|
|||||||
val actualBounds = actualTypeParameterSymbols[i].bounds
|
val actualBounds = actualTypeParameterSymbols[i].bounds
|
||||||
if (
|
if (
|
||||||
expectBounds.size != actualBounds.size ||
|
expectBounds.size != actualBounds.size ||
|
||||||
!areCompatibleTypeLists(expectBounds.map { substitutor.safeSubstitute(it) }, actualBounds)
|
!areCompatibleTypeLists(expectBounds.map { substitutor.safeSubstitute(it) }, actualBounds, insideAnnotationClass = false)
|
||||||
) {
|
) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -145,6 +145,7 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
|||||||
fun areCompatibleExpectActualTypes(
|
fun areCompatibleExpectActualTypes(
|
||||||
expectType: KotlinTypeMarker?,
|
expectType: KotlinTypeMarker?,
|
||||||
actualType: KotlinTypeMarker?,
|
actualType: KotlinTypeMarker?,
|
||||||
|
parameterOfAnnotationComparisonMode: Boolean = false,
|
||||||
): Boolean
|
): Boolean
|
||||||
|
|
||||||
fun actualTypeIsSubtypeOfExpectType(
|
fun actualTypeIsSubtypeOfExpectType(
|
||||||
|
|||||||
Vendored
+2
-2
@@ -7,7 +7,7 @@
|
|||||||
Throughput, AverageTime
|
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)
|
// MODULE: m1-jvm()()(m1-common)
|
||||||
// FILE: jvm.kt
|
// 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 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
|
// FILE: mypackage/Mode.java
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user