diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 22546b38a7c..3cc549c4b11 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -657,6 +657,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION) { firDiagnostic -> + UnsupportedInheritanceFromJavaMemberReferencingKotlinFunctionImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a), + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.CYCLIC_INHERITANCE_HIERARCHY) { firDiagnostic -> CyclicInheritanceHierarchyImpl( firDiagnostic as KtPsiDiagnostic, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 698ed11a8c7..6fc3f28e39c 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -502,6 +502,11 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { val reason: String } + interface UnsupportedInheritanceFromJavaMemberReferencingKotlinFunction : KtFirDiagnostic { + override val diagnosticClass get() = UnsupportedInheritanceFromJavaMemberReferencingKotlinFunction::class + val symbol: KtSymbol + } + interface CyclicInheritanceHierarchy : KtFirDiagnostic { override val diagnosticClass get() = CyclicInheritanceHierarchy::class } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index cf65e3833be..a60fa7a3a43 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -590,6 +590,12 @@ internal class SupertypeNotAClassOrInterfaceImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.SupertypeNotAClassOrInterface +internal class UnsupportedInheritanceFromJavaMemberReferencingKotlinFunctionImpl( + override val symbol: KtSymbol, + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.UnsupportedInheritanceFromJavaMemberReferencingKotlinFunction + internal class CyclicInheritanceHierarchyImpl( firDiagnostic: KtPsiDiagnostic, token: KtLifetimeToken, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 8f672b06045..9c8f2615006 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -248,6 +248,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val SUPERTYPE_NOT_A_CLASS_OR_INTERFACE by error { parameter("reason") } + val UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION by error(PositioningStrategy.DECLARATION_NAME) { + parameter>("symbol") + } val CYCLIC_INHERITANCE_HIERARCHY by error() val EXPANDED_TYPE_CANNOT_BE_INHERITED by error { parameter("type") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 7e2f195a328..0513ffbb14c 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -214,6 +214,7 @@ object FirErrors { val SEALED_INHERITOR_IN_DIFFERENT_MODULE by error0() val CLASS_INHERITS_JAVA_SEALED_CLASS by error0() val SUPERTYPE_NOT_A_CLASS_OR_INTERFACE by error1() + val UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION by error1>(SourceElementPositioningStrategies.DECLARATION_NAME) val CYCLIC_INHERITANCE_HIERARCHY by error0() val EXPANDED_TYPE_CANNOT_BE_INHERITED by error1() val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error0(SourceElementPositioningStrategies.VARIANCE_MODIFIER) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index b475c456f84..6db588e1fb9 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -105,6 +105,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirPrimaryConstructorSuperTypeChecker, FirDynamicSupertypeChecker, FirEnumCompanionInEnumConstructorCallChecker, + FirBadInheritedJavaSignaturesChecker, ) override val regularClassCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirBadInheritedJavaSignaturesChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirBadInheritedJavaSignaturesChecker.kt new file mode 100644 index 00000000000..83ac51f322b --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirBadInheritedJavaSignaturesChecker.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2020 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.unsubstitutedScope +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.declarations.FirClass +import org.jetbrains.kotlin.fir.declarations.isJavaOrEnhancement +import org.jetbrains.kotlin.fir.scopes.processAllCallables +import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.classId +import org.jetbrains.kotlin.fir.types.contains +import org.jetbrains.kotlin.name.StandardClassIds.Annotations.FunctionN + +object FirBadInheritedJavaSignaturesChecker : FirClassChecker() { + override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { + fun containsFunctionN(type: ConeKotlinType) = type.classId == FunctionN + + declaration.unsubstitutedScope(context).processAllCallables { symbol -> + if (!symbol.isJavaOrEnhancement) { + return@processAllCallables + } + + val hasBadReturnType = symbol.resolvedReturnType.contains(::containsFunctionN) + // NB: This case with receiver is not covered with tests + // and was replicated, because it's present in the original + // checker. + val hasBadReceiverType = symbol.resolvedReceiverTypeRef?.type?.contains(::containsFunctionN) == true + val hasBadValueParameter = symbol is FirFunctionSymbol<*> && symbol.valueParameterSymbols.any { valueParameter -> + valueParameter.resolvedReturnType.contains(::containsFunctionN) + } + + if (hasBadReturnType || hasBadReceiverType || hasBadValueParameter) { + reporter.reportOn( + declaration.source, + FirErrors.UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION, + symbol, context, + ) + } + } + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index 02f24aa8a8d..0409bbcc1d7 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -608,6 +608,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_FEATURE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_SUSPEND_TEST +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED @@ -820,6 +821,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { map.put(CLASS_INHERITS_JAVA_SEALED_CLASS, "Inheritance of Java sealed classes is prohibited") map.put(SUPERTYPE_NOT_A_CLASS_OR_INTERFACE, "Supertype is not a class or interface", TO_STRING) + map.put( + UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION, + "Inheritance of a Java member referencing 'kotlin.jvm.functions.FunctionN': {0} is unsupported", + TO_STRING, + ) map.put(CYCLIC_INHERITANCE_HIERARCHY, "There's a cycle in the inheritance hierarchy for this type") map.put( EXPANDED_TYPE_CANNOT_BE_INHERITED, diff --git a/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.fir.kt index 8ca90683387..e2037b1a9f5 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.fir.kt @@ -1,4 +1,3 @@ - // FILE: A.java import kotlin.jvm.functions.FunctionN; @@ -7,10 +6,16 @@ public class A { public void foo(FunctionN w) { } } +public class A2 { + public FunctionN foo() { } +} + // FILE: main.kt -class B : A() +class B : A() +class B2 : A2() fun foo() { - object : A() {} + object : A() {} + object : A2() {} } diff --git a/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt b/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt index cceafb98b6c..793a64c33c0 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt @@ -1,4 +1,3 @@ - // FILE: A.java import kotlin.jvm.functions.FunctionN; @@ -7,10 +6,16 @@ public class A { public void foo(FunctionN w) { } } +public class A2 { + public FunctionN foo() { } +} + // FILE: main.kt class B : A() +class B2 : A2() fun foo() { object : A() {} + object : A2() {} } diff --git a/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.txt b/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.txt deleted file mode 100644 index b07070c18f4..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.txt +++ /dev/null @@ -1,19 +0,0 @@ -package - -public fun foo(): kotlin.Unit - -public open class A { - public constructor A() - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open fun foo(/*0*/ w: kotlin.jvm.functions.FunctionN<*>!): kotlin.Unit - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} - -public final class B : A { - public constructor B() - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open override /*1*/ /*fake_override*/ fun foo(/*0*/ w: kotlin.jvm.functions.FunctionN<*>!): kotlin.Unit - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} diff --git a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt index 223517cb0c3..bb492eda396 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt @@ -14,6 +14,7 @@ object StandardClassIds { val BASE_RANGES_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("ranges")) val BASE_JVM_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("jvm")) val BASE_JVM_INTERNAL_PACKAGE = BASE_JVM_PACKAGE.child(Name.identifier("internal")) + val BASE_JVM_FUNCTIONS_PACKAGE = BASE_JVM_PACKAGE.child(Name.identifier("functions")) val BASE_ANNOTATION_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("annotation")) val BASE_INTERNAL_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("internal")) val BASE_INTERNAL_IR_PACKAGE = BASE_INTERNAL_PACKAGE.child(Name.identifier("ir")) @@ -183,6 +184,8 @@ object StandardClassIds { val FlexibleMutability = "FlexibleMutability".internalIrId() val EnhancedNullability = "EnhancedNullability".jvmInternalId() + val FunctionN = "FunctionN".jvmFunctionsId() + val InlineOnly = "InlineOnly".internalId() val OnlyInputTypes = "OnlyInputTypes".internalId() @@ -265,6 +268,7 @@ private fun String.rangesId() = ClassId(StandardClassIds.BASE_RANGES_PACKAGE, Na private fun String.annotationId() = ClassId(StandardClassIds.BASE_ANNOTATION_PACKAGE, Name.identifier(this)) private fun String.jvmId() = ClassId(StandardClassIds.BASE_JVM_PACKAGE, Name.identifier(this)) private fun String.jvmInternalId() = ClassId(StandardClassIds.BASE_JVM_INTERNAL_PACKAGE, Name.identifier(this)) +private fun String.jvmFunctionsId() = ClassId(StandardClassIds.BASE_JVM_FUNCTIONS_PACKAGE, Name.identifier(this)) private fun String.internalId() = ClassId(StandardClassIds.BASE_INTERNAL_PACKAGE, Name.identifier(this)) private fun String.internalIrId() = ClassId(StandardClassIds.BASE_INTERNAL_IR_PACKAGE, Name.identifier(this)) private fun String.coroutinesId() = ClassId(StandardClassIds.BASE_COROUTINES_PACKAGE, Name.identifier(this))