[FIR] 2/2 Cleanup: drop no longer necessary FirActualCallableDeclarationChecker
It became possible to drop it after KT-62590. Now, on a frontend, the return type check is part of a common AbstractExpectActualChecker logic Change in nestedAnnotationClassViaActualTypealias.fir.kt aligns the behaviour with K1. KT-61964 Review: https://jetbrains.team/p/kt/reviews/12750/timeline
This commit is contained in:
-1
@@ -49,7 +49,6 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
|||||||
FirKClassWithIncorrectTypeArgumentChecker,
|
FirKClassWithIncorrectTypeArgumentChecker,
|
||||||
FirImplicitNothingReturnTypeChecker,
|
FirImplicitNothingReturnTypeChecker,
|
||||||
FirDynamicReceiverChecker,
|
FirDynamicReceiverChecker,
|
||||||
FirActualCallableDeclarationChecker,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
override val functionCheckers: Set<FirFunctionChecker>
|
override val functionCheckers: Set<FirFunctionChecker>
|
||||||
|
|||||||
-69
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.fir.analysis.checkers.declaration
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.expectForActual
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.getSingleExpectForActualOrNull
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isActual
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.types.areCompatibleExpectActualTypes
|
|
||||||
import org.jetbrains.kotlin.fir.types.createExpectActualTypeParameterSubstitutor
|
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMatchingCompatibility
|
|
||||||
import org.jetbrains.kotlin.utils.zipIfSizesAreEqual
|
|
||||||
|
|
||||||
object FirActualCallableDeclarationChecker : FirCallableDeclarationChecker() {
|
|
||||||
override fun check(declaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
|
||||||
if (!declaration.isActual) return
|
|
||||||
|
|
||||||
checkReturnTypes(declaration, context, reporter)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkReturnTypes(callableDeclaration: FirCallableDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
|
||||||
val actualFunctionSymbol = callableDeclaration.symbol
|
|
||||||
val expectFunctionSymbol = actualFunctionSymbol.getSingleExpectForActualOrNull() as? FirCallableSymbol ?: return
|
|
||||||
|
|
||||||
val expectTypeParameters = expectFunctionSymbol.getContainingClassSymbol(expectFunctionSymbol.moduleData.session)
|
|
||||||
?.typeParameterSymbols.orEmpty()
|
|
||||||
val actualClassTypeParameters = actualFunctionSymbol.getContainingClassSymbol(context.session)?.typeParameterSymbols.orEmpty()
|
|
||||||
|
|
||||||
val parentSubstitutor = createExpectActualTypeParameterSubstitutor(
|
|
||||||
// It's responsibility of AbstractExpectActualCompatibilityChecker to report that
|
|
||||||
(expectTypeParameters zipIfSizesAreEqual actualClassTypeParameters) ?: return,
|
|
||||||
context.session
|
|
||||||
)
|
|
||||||
|
|
||||||
val substitutor = createExpectActualTypeParameterSubstitutor(
|
|
||||||
// It's responsibility of AbstractExpectActualCompatibilityChecker to check that
|
|
||||||
(expectFunctionSymbol.typeParameterSymbols zipIfSizesAreEqual actualFunctionSymbol.typeParameterSymbols) ?: return,
|
|
||||||
context.session,
|
|
||||||
parentSubstitutor
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!areCompatibleExpectActualTypes(
|
|
||||||
substitutor.substituteOrSelf(expectFunctionSymbol.resolvedReturnType.type),
|
|
||||||
actualFunctionSymbol.resolvedReturnType.type,
|
|
||||||
context.session,
|
|
||||||
dynamicTypesEqualToAnything = false
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
reporter.reportOn(
|
|
||||||
callableDeclaration.source,
|
|
||||||
FirErrors.ACTUAL_WITHOUT_EXPECT,
|
|
||||||
actualFunctionSymbol,
|
|
||||||
actualFunctionSymbol.expectForActual as Map<ExpectActualMatchingCompatibility, Collection<FirBasedSymbol<*>>>,
|
|
||||||
context
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
|||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.chain
|
import org.jetbrains.kotlin.fir.resolve.substitution.chain
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
|
||||||
|
|
||||||
fun createExpectActualTypeParameterSubstitutor(
|
fun createExpectActualTypeParameterSubstitutor(
|
||||||
expectActualTypeParameters: List<Pair<FirTypeParameterSymbol, FirTypeParameterSymbol>>,
|
expectActualTypeParameters: List<Pair<FirTypeParameterSymbol, FirTypeParameterSymbol>>,
|
||||||
@@ -29,28 +28,3 @@ fun createExpectActualTypeParameterSubstitutor(
|
|||||||
}
|
}
|
||||||
return substitutor.chain(parentSubstitutor)
|
return substitutor.chain(parentSubstitutor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy-pasted to org.jetbrains.kotlin.fir.resolve.transformers.mpp.FirExpectActualMatchingContextImpl.areCompatibleExpectActualTypes
|
|
||||||
fun areCompatibleExpectActualTypes(
|
|
||||||
expectedType: ConeKotlinType?,
|
|
||||||
actualType: ConeKotlinType?,
|
|
||||||
actualSession: FirSession,
|
|
||||||
dynamicTypesEqualToAnything: Boolean = true
|
|
||||||
): Boolean {
|
|
||||||
if (expectedType == null) return actualType == null
|
|
||||||
if (actualType == null) return false
|
|
||||||
|
|
||||||
if (!dynamicTypesEqualToAnything) {
|
|
||||||
val isExpectedDynamic = expectedType is ConeDynamicType
|
|
||||||
val isActualDynamic = actualType is ConeDynamicType
|
|
||||||
if (isExpectedDynamic && !isActualDynamic || !isExpectedDynamic && isActualDynamic) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return AbstractTypeChecker.equalTypes(
|
|
||||||
actualSession.typeContext,
|
|
||||||
expectedType,
|
|
||||||
actualType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
-4
@@ -43,9 +43,6 @@ class FirExpectActualMatchingContextImpl private constructor(
|
|||||||
private val scopeSession: ScopeSession,
|
private val scopeSession: ScopeSession,
|
||||||
private val allowedWritingMemberExpectForActualMapping: Boolean,
|
private val allowedWritingMemberExpectForActualMapping: Boolean,
|
||||||
) : FirExpectActualMatchingContext, TypeSystemContext by actualSession.typeContext {
|
) : FirExpectActualMatchingContext, TypeSystemContext by actualSession.typeContext {
|
||||||
override val shouldCheckReturnTypesOfCallables: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
override val shouldCheckAbsenceOfDefaultParamsInActual: Boolean
|
override val shouldCheckAbsenceOfDefaultParamsInActual: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
|
|
||||||
@@ -303,7 +300,6 @@ class FirExpectActualMatchingContextImpl private constructor(
|
|||||||
override val TypeParameterSymbolMarker.isReified: Boolean
|
override val TypeParameterSymbolMarker.isReified: Boolean
|
||||||
get() = asSymbol().isReified
|
get() = asSymbol().isReified
|
||||||
|
|
||||||
// Copy-pasted to org.jetbrains.kotlin.fir.types.ExpectActualUtilsKt.areCompatibleExpectActualTypes
|
|
||||||
override fun areCompatibleExpectActualTypes(
|
override fun areCompatibleExpectActualTypes(
|
||||||
expectType: KotlinTypeMarker?,
|
expectType: KotlinTypeMarker?,
|
||||||
actualType: KotlinTypeMarker?,
|
actualType: KotlinTypeMarker?,
|
||||||
|
|||||||
-3
@@ -92,9 +92,6 @@ internal abstract class IrExpectActualMatchingContext(
|
|||||||
|
|
||||||
private inline fun <reified T : IrDeclaration> DeclarationSymbolMarker.safeAsIr(): T? = (this as IrSymbol).owner as? T
|
private inline fun <reified T : IrDeclaration> DeclarationSymbolMarker.safeAsIr(): T? = (this as IrSymbol).owner as? T
|
||||||
|
|
||||||
override val shouldCheckReturnTypesOfCallables: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override val innerClassesCapturesOuterTypeParameters: Boolean
|
override val innerClassesCapturesOuterTypeParameters: Boolean
|
||||||
get() = false
|
get() = false
|
||||||
|
|
||||||
|
|||||||
+13
-15
@@ -362,22 +362,20 @@ object AbstractExpectActualChecker {
|
|||||||
val expectedValueParameters = expectDeclaration.valueParameters
|
val expectedValueParameters = expectDeclaration.valueParameters
|
||||||
val actualValueParameters = actualDeclaration.valueParameters
|
val actualValueParameters = actualDeclaration.valueParameters
|
||||||
|
|
||||||
if (shouldCheckReturnTypesOfCallables) {
|
val substitutor = createExpectActualTypeParameterSubstitutor(
|
||||||
val substitutor = createExpectActualTypeParameterSubstitutor(
|
(expectedTypeParameters zipIfSizesAreEqual actualTypeParameters)
|
||||||
(expectedTypeParameters zipIfSizesAreEqual actualTypeParameters)
|
?: error("expect/actual type parameters sizes are checked earlier"),
|
||||||
?: error("expect/actual type parameters sizes are checked earlier"),
|
parentSubstitutor
|
||||||
parentSubstitutor
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if (!areCompatibleExpectActualTypes(
|
if (!areCompatibleExpectActualTypes(
|
||||||
substitutor.safeSubstitute(expectDeclaration.returnType),
|
substitutor.safeSubstitute(expectDeclaration.returnType),
|
||||||
actualDeclaration.returnType,
|
actualDeclaration.returnType,
|
||||||
parameterOfAnnotationComparisonMode = insideAnnotationClass,
|
parameterOfAnnotationComparisonMode = insideAnnotationClass,
|
||||||
dynamicTypesEqualToAnything = false
|
dynamicTypesEqualToAnything = false
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return ExpectActualCheckingCompatibility.ReturnType
|
return ExpectActualCheckingCompatibility.ReturnType
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actualDeclaration.hasStableParameterNames && !equalsBy(expectedValueParameters, actualValueParameters) { it.name }) {
|
if (actualDeclaration.hasStableParameterNames && !equalsBy(expectedValueParameters, actualValueParameters) { it.name }) {
|
||||||
|
|||||||
-2
@@ -20,8 +20,6 @@ import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker
|
|||||||
import org.jetbrains.kotlin.types.model.TypeSystemContext
|
import org.jetbrains.kotlin.types.model.TypeSystemContext
|
||||||
|
|
||||||
interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemContext {
|
interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemContext {
|
||||||
val shouldCheckReturnTypesOfCallables: Boolean
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This flag indicates how are type parameters of inner classes stored in the specific implementation of RegularClassSymbolMarker
|
* This flag indicates how are type parameters of inner classes stored in the specific implementation of RegularClassSymbolMarker
|
||||||
*
|
*
|
||||||
|
|||||||
+1
-1
@@ -11,4 +11,4 @@ class DefaultArgsInNestedClassImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Incompatible because of bug KT-31636
|
// Incompatible because of bug KT-31636
|
||||||
actual typealias DefaultArgsInNestedClass = DefaultArgsInNestedClassImpl
|
actual typealias <!NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS!>DefaultArgsInNestedClass<!> = DefaultArgsInNestedClassImpl
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ interface KotlinXStringDemoInterface {
|
|||||||
// FILE: StringDemoInterface.kt
|
// FILE: StringDemoInterface.kt
|
||||||
actual typealias StringDemoInterface = KotlinXStringDemoInterface
|
actual typealias StringDemoInterface = KotlinXStringDemoInterface
|
||||||
|
|
||||||
actual fun StringDemoIn<!EXPECT_ACTUAL_INCOMPATIBILITY!>terface.<!ACTUAL_WITHOUT_EXPECT("actual fun StringDemoInterface.plusK(): <ERROR TYPE REF: Unresolved name: value>; The following declaration is incompatible: expect fun StringDemoInterface.plusK(): String")!>plusK<!>() = <!EXPECT_CLASS_AS_FUNCTION!>StringValue<!>(value).plus("K")<!>.<!UNRESOLVED_REFERENCE!>value<!>
|
actual fun StringDemoIn<!EXPECT_ACTUAL_INCOMPATIBILITY!>terface.<!ACTUAL_WITHOUT_EXPECT("actual fun StringDemoInterface.plusK(): <ERROR TYPE REF: Unresolved name: value>; The following declaration is incompatible because return type is different: expect fun StringDemoInterface.plusK(): String")!>plusK<!>() = <!EXPECT_CLASS_AS_FUNCTION!>StringValue<!>(value).plus("K")<!>.<!UNRESOLVED_REFERENCE!>value<!>
|
||||||
|
|
||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
class StringDemo(override val value: String) : StringDemoInterface
|
class StringDemo(override val value: String) : StringDemoInterface
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ Output:
|
|||||||
Exit code: COMPILATION_ERROR
|
Exit code: COMPILATION_ERROR
|
||||||
Output:
|
Output:
|
||||||
compiler/testData/multiplatform/classScopes/functionIncorrectSignature/jvm.kt:2:16: error: 'actual fun function(b: ByteArray): Long' has no corresponding expected declaration
|
compiler/testData/multiplatform/classScopes/functionIncorrectSignature/jvm.kt:2:16: error: 'actual fun function(b: ByteArray): Long' has no corresponding expected declaration
|
||||||
The following declaration is incompatible:
|
The following declaration is incompatible because return type is different:
|
||||||
expect fun function(b: ByteArray): Int
|
expect fun function(b: ByteArray): Int
|
||||||
|
|
||||||
actual fun function(b: ByteArray): Long = b.size.toLong()
|
actual fun function(b: ByteArray): Long = b.size.toLong()
|
||||||
|
|||||||
Vendored
+9
-6
@@ -5,9 +5,12 @@ Output:
|
|||||||
-- JVM --
|
-- JVM --
|
||||||
Exit code: COMPILATION_ERROR
|
Exit code: COMPILATION_ERROR
|
||||||
Output:
|
Output:
|
||||||
compiler/testData/multiplatform/classScopes/functionIncorrectSignatureFromSuperclass/common.kt:1:1: error: expect declaration `Foo` doesn't match actual `Foo` because some expected members have no actual ones
|
compiler/testData/multiplatform/classScopes/functionIncorrectSignatureFromSuperclass/jvm.kt:5:14: error: 'actual class Foo : Base' has no corresponding members for expected class members:
|
||||||
expect class Foo {
|
|
||||||
^
|
expect fun function(b: ByteArray): Int
|
||||||
compiler/testData/multiplatform/classScopes/functionIncorrectSignatureFromSuperclass/common.kt:2:5: error: expect declaration `function` doesn't match actual `function` because return type is different
|
|
||||||
fun function(b: ByteArray): Int
|
The following declaration is incompatible because return type is different:
|
||||||
^
|
fun function(b: ByteArray): Long
|
||||||
|
|
||||||
|
actual class Foo : Base()
|
||||||
|
^
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Output:
|
|||||||
Exit code: COMPILATION_ERROR
|
Exit code: COMPILATION_ERROR
|
||||||
Output:
|
Output:
|
||||||
compiler/testData/multiplatform/incompatibleCallables/jvm.kt:1:12: error: 'actual fun f1(): String' has no corresponding expected declaration
|
compiler/testData/multiplatform/incompatibleCallables/jvm.kt:1:12: error: 'actual fun f1(): String' has no corresponding expected declaration
|
||||||
The following declaration is incompatible:
|
The following declaration is incompatible because return type is different:
|
||||||
expect fun f1(): Unit
|
expect fun f1(): Unit
|
||||||
|
|
||||||
actual fun f1(): String = ""
|
actual fun f1(): String = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user