From 4958196c51b017d3b1d061ffbc01cd9de57aa66f Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Thu, 17 Aug 2023 13:40:54 +0300 Subject: [PATCH] [FIR] Forbid mixing supertypes with different functional kinds ^KT-61277 Fixed --- .../diagnostics/KtFirDataClassConverters.kt | 9 +++++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 5 ++++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 6 +++++ .../diagnostics/FirDiagnosticsList.kt | 3 +++ .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../checkers/CommonDeclarationCheckers.kt | 2 +- ...ixedFunctionalTypesInSupertypesChecker.kt} | 23 +++++++++-------- .../diagnostics/FirErrorsDefaultMessages.kt | 6 +++++ ...mixingComposableAndNormalFunctions.fir.txt | 25 +++++++++++++++++++ .../mixingComposableAndNormalFunctions.kt | 8 ++++++ .../FirPsiPluginDiagnosticTestGenerated.java | 6 +++++ 11 files changed, 83 insertions(+), 11 deletions(-) rename compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/{FirSuspendFunctionAsSupertypeChecker.kt => FirMixedFunctionalTypesInSupertypesChecker.kt} (51%) create mode 100644 plugins/fir-plugin-prototype/testData/diagnostics/checkers/mixingComposableAndNormalFunctions.fir.txt create mode 100644 plugins/fir-plugin-prototype/testData/diagnostics/checkers/mixingComposableAndNormalFunctions.kt 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 98f98510517..60fe67d2353 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 @@ -4671,6 +4671,15 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.MIXING_FUNCTIONAL_KINDS_IN_SUPERTYPES) { firDiagnostic -> + MixingFunctionalKindsInSupertypesImpl( + firDiagnostic.a.map { functionTypeKind -> + functionTypeKind + }, + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.REDUNDANT_LABEL_WARNING) { firDiagnostic -> RedundantLabelWarningImpl( 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 569b54d71f6..2c0ec66ccb0 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 @@ -3260,6 +3260,11 @@ sealed interface KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = MixingSuspendAndNonSuspendSupertypes::class } + interface MixingFunctionalKindsInSupertypes : KtFirDiagnostic { + override val diagnosticClass get() = MixingFunctionalKindsInSupertypes::class + val kinds: List + } + interface RedundantLabelWarning : KtFirDiagnostic { override val diagnosticClass get() = RedundantLabelWarning::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 345b35cce67..2c912afce13 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 @@ -3933,6 +3933,12 @@ internal class MixingSuspendAndNonSuspendSupertypesImpl( token: KtLifetimeToken, ) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.MixingSuspendAndNonSuspendSupertypes +internal class MixingFunctionalKindsInSupertypesImpl( + override val kinds: List, + firDiagnostic: KtPsiDiagnostic, + token: KtLifetimeToken, +) : KtAbstractFirDiagnostic(firDiagnostic, token), KtFirDiagnostic.MixingFunctionalKindsInSupertypes + internal class RedundantLabelWarningImpl( 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 c21fe6d5e57..ac2ec740afa 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 @@ -1650,6 +1650,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { ) val RETURN_FOR_BUILT_IN_SUSPEND by error() val MIXING_SUSPEND_AND_NON_SUSPEND_SUPERTYPES by error(PositioningStrategy.SUPERTYPES_LIST) + val MIXING_FUNCTIONAL_KINDS_IN_SUPERTYPES by error(PositioningStrategy.SUPERTYPES_LIST) { + parameter>("kinds") + } } val LABEL by object : DiagnosticGroup("label") { 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 69f355afc62..42dddd84ece 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 @@ -827,6 +827,7 @@ object FirErrors { val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN by deprecationError0(ModifierNonBuiltinSuspendFunError, SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val RETURN_FOR_BUILT_IN_SUSPEND by error0() val MIXING_SUSPEND_AND_NON_SUSPEND_SUPERTYPES by error0(SourceElementPositioningStrategies.SUPERTYPES_LIST) + val MIXING_FUNCTIONAL_KINDS_IN_SUPERTYPES by error1>(SourceElementPositioningStrategies.SUPERTYPES_LIST) // label val REDUNDANT_LABEL_WARNING by warning0(SourceElementPositioningStrategies.LABEL) 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 4fbe57ad06e..17f0586d182 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 @@ -109,7 +109,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirEnumCompanionInEnumConstructorCallChecker, FirBadInheritedJavaSignaturesChecker, FirSealedInterfaceAllowedChecker, - FirSuspendFunctionAsSupertypeChecker, + FirMixedFunctionalTypesInSupertypesChecker, ) override val regularClassCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSuspendFunctionAsSupertypeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMixedFunctionalTypesInSupertypesChecker.kt similarity index 51% rename from compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSuspendFunctionAsSupertypeChecker.kt rename to compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMixedFunctionalTypesInSupertypesChecker.kt index 3e26c1ac00e..0e58d5e5fb9 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSuspendFunctionAsSupertypeChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMixedFunctionalTypesInSupertypesChecker.kt @@ -5,8 +5,8 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration -import org.jetbrains.kotlin.builtins.functions.isBasicFunctionOrKFunction -import org.jetbrains.kotlin.builtins.functions.isSuspendOrKSuspendFunction +import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind.Function +import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind.SuspendFunction import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext @@ -15,16 +15,19 @@ import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes import org.jetbrains.kotlin.fir.types.functionTypeKind -object FirSuspendFunctionAsSupertypeChecker : FirClassChecker() { +object FirMixedFunctionalTypesInSupertypesChecker : FirClassChecker() { override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) { - val supertypes = lookupSuperTypes(declaration.symbol, lookupInterfaces = true, deep = true, context.session) - .mapNotNull { it.functionTypeKind(context.session) } + val superKinds = lookupSuperTypes(declaration.symbol, lookupInterfaces = true, deep = true, context.session) + .mapNotNullTo(mutableSetOf()) { it.functionTypeKind(context.session)?.nonReflectKind() } - if ( - supertypes.any { it.isSuspendOrKSuspendFunction } && - supertypes.any { it.isBasicFunctionOrKFunction } - ) { - reporter.reportOn(declaration.source, FirErrors.MIXING_SUSPEND_AND_NON_SUSPEND_SUPERTYPES, context) + when { + superKinds.size <= 1 -> {} + superKinds == setOf(Function, SuspendFunction) -> { + reporter.reportOn(declaration.source, FirErrors.MIXING_SUSPEND_AND_NON_SUSPEND_SUPERTYPES, context) + } + else -> { + reporter.reportOn(declaration.source, FirErrors.MIXING_FUNCTIONAL_KINDS_IN_SUPERTYPES, superKinds, 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 a40ccf6ce46..6c3e741c4d5 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 @@ -356,6 +356,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.METHOD_OF_ANY_IMP import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISPLACED_TYPE_PARAMETER_CONSTRAINTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_STDLIB_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MISSING_VAL_ON_ANNOTATION_PARAMETER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MIXING_FUNCTIONAL_KINDS_IN_SUPERTYPES import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MIXING_SUSPEND_AND_NON_SUSPEND_SUPERTYPES import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN @@ -2349,6 +2350,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { ) map.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited") map.put(MIXING_SUSPEND_AND_NON_SUSPEND_SUPERTYPES, "Mixing suspend and non-suspend supertypes is not allowed") + map.put( + MIXING_FUNCTIONAL_KINDS_IN_SUPERTYPES, + "Mixing supertypes of different functional kinds ({0}) is not allowed.", + FUNCTIONAL_TYPE_KINDS, + ) // Label map.put( diff --git a/plugins/fir-plugin-prototype/testData/diagnostics/checkers/mixingComposableAndNormalFunctions.fir.txt b/plugins/fir-plugin-prototype/testData/diagnostics/checkers/mixingComposableAndNormalFunctions.fir.txt new file mode 100644 index 00000000000..1dd39d750a8 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/diagnostics/checkers/mixingComposableAndNormalFunctions.fir.txt @@ -0,0 +1,25 @@ +FILE: mixingComposableAndNormalFunctions.kt + public abstract class MyClass : R|kotlin/reflect/KSuspendFunction0|, R|() -> kotlin/Unit| { + public constructor(): R|MyClass| { + super() + } + + } + public abstract class OurClass : R|@R|org/jetbrains/kotlin/fir/plugin/MyComposable|() some/MyComposableFunction1|, R|() -> kotlin/Unit| { + public constructor(): R|OurClass| { + super() + } + + } + public abstract class YourClass : R|@R|org/jetbrains/kotlin/fir/plugin/MyComposable|() kotlin/reflect/KFunction1|, R|() -> kotlin/Unit| { + public constructor(): R|YourClass| { + super() + } + + } + public abstract class Their : R|kotlin/reflect/KSuspendFunction1|, R|() -> kotlin/Unit| { + public constructor(): R|Their| { + super() + } + + } diff --git a/plugins/fir-plugin-prototype/testData/diagnostics/checkers/mixingComposableAndNormalFunctions.kt b/plugins/fir-plugin-prototype/testData/diagnostics/checkers/mixingComposableAndNormalFunctions.kt new file mode 100644 index 00000000000..bc9c3ad1e22 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/diagnostics/checkers/mixingComposableAndNormalFunctions.kt @@ -0,0 +1,8 @@ +import org.jetbrains.kotlin.fir.plugin.MyComposable +import kotlin.reflect.* + +abstract class MyClass: KSuspendFunction0, () -> Unit +abstract class OurClass: @MyComposable (Int) -> Unit, () -> Unit + +abstract class YourClass: @MyComposable KFunction1, () -> Unit +abstract class Their: KSuspendFunction1, () -> Unit diff --git a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPsiPluginDiagnosticTestGenerated.java b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPsiPluginDiagnosticTestGenerated.java index e7548901c38..5f2189c43bd 100644 --- a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPsiPluginDiagnosticTestGenerated.java +++ b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPsiPluginDiagnosticTestGenerated.java @@ -39,6 +39,12 @@ public class FirPsiPluginDiagnosticTestGenerated extends AbstractFirPsiPluginDia runTest("plugins/fir-plugin-prototype/testData/diagnostics/checkers/dependencyWithoutAttributePlugin.kt"); } + @Test + @TestMetadata("mixingComposableAndNormalFunctions.kt") + public void testMixingComposableAndNormalFunctions() throws Exception { + runTest("plugins/fir-plugin-prototype/testData/diagnostics/checkers/mixingComposableAndNormalFunctions.kt"); + } + @Test @TestMetadata("signedNumbersCheckers.kt") public void testSignedNumbersCheckers() throws Exception {