diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index d3245abcf75..757372bb238 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -179,6 +179,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/ft.kt"); } + @TestMetadata("funInterfaceDeclaration.kt") + public void testFunInterfaceDeclaration() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/funInterfaceDeclaration.kt"); + } + @TestMetadata("functionTypeAlias.kt") public void testFunctionTypeAlias() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/functionTypeAlias.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/funInterfaceDeclaration.fir.txt b/compiler/fir/analysis-tests/testData/resolve/funInterfaceDeclaration.fir.txt new file mode 100644 index 00000000000..72b9a08afce --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/funInterfaceDeclaration.fir.txt @@ -0,0 +1,55 @@ +FILE: funInterfaceDeclaration.kt + public abstract interface Test1 : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + public abstract fun boo(): R|kotlin/Unit| + + } + public abstract interface Test2 : R|kotlin/Any| { + } + public abstract interface Test3 : R|kotlin/Any| { + public abstract val a: R|kotlin/Int| + public get(): R|kotlin/Int| + + public abstract fun foo(): R|kotlin/Unit| + + } + public abstract interface Test4 : R|kotlin/Any| { + public abstract fun foo(a: R|T|): R|kotlin/Unit| + + } + public abstract interface Test5 : R|kotlin/Any| { + public abstract fun foo(a: R|kotlin/Int| = Int(5)): R|kotlin/Unit| + + } + public abstract interface Test6 : R|kotlin/Any| { + public abstract suspend fun foo(): R|kotlin/Unit| + + } + public abstract interface Test7 : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + } + public abstract interface Test8 : R|Test7| { + public abstract fun boo(): R|kotlin/Unit| + + } + public abstract interface Test9 : R|kotlin/Any| { + public open fun num(m: R|kotlin/Int|): R|kotlin/Int| { + ^num R|/m|.R|kotlin/Int.times|(R|/m|) + } + + } + public abstract interface Test10 : R|Test9| { + public abstract fun test(): R|kotlin/Unit| + + } + public abstract interface Test11 : R|kotlin/Any| { + public abstract val a: R|kotlin/Int| + public get(): R|kotlin/Int| + + } + public abstract interface Test12 : R|Test11| { + public abstract fun test(): R|kotlin/Unit| + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/funInterfaceDeclaration.kt b/compiler/fir/analysis-tests/testData/resolve/funInterfaceDeclaration.kt new file mode 100644 index 00000000000..2905d35fc64 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/funInterfaceDeclaration.kt @@ -0,0 +1,38 @@ +fun interface Test1{ + fun foo() + fun boo() +} +fun interface Test2 {} +fun interface Test3 { + val a: Int + fun foo() +} +fun interface Test4{ + fun <T> foo(a: T) +} +fun interface Test5{ + fun foo(a: Int = 5) +} +fun interface Test6{ + suspend fun foo() +} +fun interface Test7{ + fun foo() +} +fun interface Test8: Test7{ + fun boo() +} +interface Test9 { + fun num(m: Int): Int { + return m * m + } +} +fun interface Test10 : Test9 { + fun test() +} +interface Test11 { + val a: Int +} +fun interface Test12 : Test11 { + fun test() +} diff --git a/compiler/fir/analysis-tests/testData/resolve/samConversions/kotlinSam.kt b/compiler/fir/analysis-tests/testData/resolve/samConversions/kotlinSam.kt index 9993c16eaf8..cd4b1791d65 100644 --- a/compiler/fir/analysis-tests/testData/resolve/samConversions/kotlinSam.kt +++ b/compiler/fir/analysis-tests/testData/resolve/samConversions/kotlinSam.kt @@ -2,11 +2,11 @@ fun interface MyRunnable { fun foo(x: Int): Boolean } -fun interface WithProperty { - val x: Int +fun interface WithProperty { + val x: Int } -fun interface TwoAbstract : MyRunnable { +fun interface TwoAbstract : MyRunnable { fun bar() } diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index 927e22f09b6..a3540c37d43 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -206,6 +206,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/ft.kt"); } + @Test + @TestMetadata("funInterfaceDeclaration.kt") + public void testFunInterfaceDeclaration() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/funInterfaceDeclaration.kt"); + } + @Test @TestMetadata("functionTypeAlias.kt") public void testFunctionTypeAlias() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 0ae16964aff..cc5062f2deb 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -206,6 +206,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/ft.kt"); } + @Test + @TestMetadata("funInterfaceDeclaration.kt") + public void testFunInterfaceDeclaration() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/funInterfaceDeclaration.kt"); + } + @Test @TestMetadata("functionTypeAlias.kt") public void testFunctionTypeAlias() throws Exception { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt index 6cbd2b5ea21..f81e6743d3c 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt @@ -64,6 +64,9 @@ enum class PositioningStrategy(private val strategy: String? = null) { LONG_LITERAL_SUFFIX, REIFIED_MODIFIER, TYPE_PARAMETERS_LIST, + FUN_MODIFIER, + SUSPEND_MODIFIER, + FUN_INTERFACE_ABSTRACT_PROPERTY, ; 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 6f90ea1d383..becdd036846 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 @@ -14,7 +14,6 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.diagnostics.WhenMissingCase -import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.PrivateForInline import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirExpression @@ -500,6 +499,11 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val FUN_INTERFACES by object : DiagnosticGroup("Fun interfaces") { val FUN_INTERFACE_CONSTRUCTOR_REFERENCE by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) + val FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS by error(PositioningStrategy.FUN_MODIFIER) + val FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES by error(PositioningStrategy.FUN_INTERFACE_ABSTRACT_PROPERTY) + val FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS by error() + val FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE by error() + val FUN_INTERFACE_WITH_SUSPEND_FUNCTION by error(PositioningStrategy.SUSPEND_MODIFIER) } val PROPERTIES_AND_ACCESSORS by object : DiagnosticGroup("Properties & accessors") { 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 0c6c81a9d87..82da6970cbe 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 @@ -310,6 +310,11 @@ object FirErrors { // Fun interfaces val FUN_INTERFACE_CONSTRUCTOR_REFERENCE by error0(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) + val FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS by error0(SourceElementPositioningStrategies.FUN_MODIFIER) + val FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES by error0(SourceElementPositioningStrategies.FUN_INTERFACE_ABSTRACT_PROPERTY) + val FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS by error0() + val FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE by error0() + val FUN_INTERFACE_WITH_SUSPEND_FUNCTION by error0(SourceElementPositioningStrategies.SUSPEND_MODIFIER) // Properties & accessors val ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS by error2(SourceElementPositioningStrategies.MODALITY_MODIFIER) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunInterfaceDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunInterfaceDeclarationChecker.kt new file mode 100644 index 00000000000..367a0de2f57 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirFunInterfaceDeclarationChecker.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2021 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.config.LanguageFeature +import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClass +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WITH_SUSPEND_FUNCTION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.scopes.getFunctions +import org.jetbrains.kotlin.fir.scopes.getProperties + +object FirFunInterfaceDeclarationChecker : FirRegularClassChecker() { + + override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) { + if (!declaration.isInterface || !declaration.isFun) return + + val scope = declaration.unsubstitutedScope(context) + + var abstractFunction: FirSimpleFunction? = null + + for (name in scope.getCallableNames()) { + val functions = scope.getFunctions(name) + val properties = scope.getProperties(name) + + for (function in functions) { + if (function.fir.isAbstract) { + if (abstractFunction == null) { + abstractFunction = function.fir + } else { + reporter.reportOn(declaration.source, FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS, context) + } + } + } + + for (property in properties) { + val firProperty = property.fir as? FirProperty ?: continue + if (firProperty.isAbstract) { + val source = + if (firProperty.getContainingClass(context) != declaration) + declaration.source + else + firProperty.source + + reporter.reportOn(source, FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES, context) + } + } + } + + if (abstractFunction == null) { + reporter.reportOn(declaration.source, FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS, context) + return + } + + when { + abstractFunction.typeParameters.isNotEmpty() -> + reporter.reportOn( + abstractFunction.typeParameters.first().source, + FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS, + context + ) + + abstractFunction.isSuspend -> + if (!context.session.languageVersionSettings.supportsFeature(LanguageFeature.SuspendFunctionsInFunInterfaces)) { + reporter.reportOn(abstractFunction.source, FUN_INTERFACE_WITH_SUSPEND_FUNCTION, context) + } + } + + abstractFunction.valueParameters.forEach { + if (it.defaultValue != null) { + reporter.reportOn(it.source, FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE, context) + } + } + } +} + diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 84b1d745b5b..fe0ab6f790a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -111,8 +111,13 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERTY_WITH_BACKING_FIELD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FINAL_UPPER_BOUND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FORBIDDEN_VARARG_PARAMETER_TYPE -import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WITH_SUSPEND_FUNCTION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GENERIC_THROWABLE_SUBCLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_AMBIGUITY @@ -698,6 +703,15 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { "An anonymous function is not allowed to specify default values for its parameters" ) map.put(USELESS_VARARG_ON_PARAMETER, "Vararg on this parameter is useless") + map.put( + FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS, + "Fun interface must have exactly one abstract function" + ) + map.put(FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES, "Fun interface can not have abstract properties") + map.put(FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS, "Fun interface can not have abstract metod with type parameters") + map.put(FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE, "Fun interface abstract method can not have default value") + map.put(FUN_INTERFACE_WITH_SUSPEND_FUNCTION, "Fun interface abstract method can not be suspend") + map.put(MULTIPLE_VARARG_PARAMETERS, "Multiple vararg-parameters are prohibited") map.put(FORBIDDEN_VARARG_PARAMETER_TYPE, "Forbidden vararg parameter type: {0}", RENDER_TYPE) map.put(VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION, "A type annotation is required on a value parameter") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt index 29c061193a2..e2d45305385 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt @@ -340,6 +340,12 @@ object LightTreePositioningStrategies { val CONST_MODIFIER: LightTreePositioningStrategy = ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.CONST_KEYWORD)) + val FUN_MODIFIER: LightTreePositioningStrategy = + ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.FUN_KEYWORD)) + + val SUSPEND_MODIFIER: LightTreePositioningStrategy = + ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.SUSPEND_KEYWORD)) + val INLINE_OR_VALUE_MODIFIER: LightTreePositioningStrategy = ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.INLINE_KEYWORD, KtTokens.VALUE_KEYWORD)) @@ -443,6 +449,22 @@ object LightTreePositioningStrategies { } } + val FUN_INTERFACE_ABSTRACT_PROPERTY: LightTreePositioningStrategy = object : LightTreePositioningStrategy() { + override fun mark( + node: LighterASTNode, + startOffset: Int, + endOffset: Int, + tree: FlyweightCapableTreeStructure + ): List { + return when (node.tokenType) { + KtNodeTypes.CLASS -> FUN_MODIFIER.mark(node, startOffset, endOffset, tree) + KtNodeTypes.PROPERTY -> VAL_OR_VAR_NODE.mark(node, startOffset, endOffset, tree) + else -> DEFAULT.mark(node, startOffset, endOffset, tree) + } + } + } + + val REFERENCE_BY_QUALIFIED: LightTreePositioningStrategy = FindReferencePositioningStrategy(false) val REFERENCED_NAME_BY_QUALIFIED: LightTreePositioningStrategy = FindReferencePositioningStrategy(true) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt index 5d8271f9a34..1d0a4f5b76b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt @@ -18,6 +18,11 @@ object SourceElementPositioningStrategies { PositioningStrategies.VAL_OR_VAR_NODE ) + val FUN_INTERFACE_ABSTRACT_PROPERTY = SourceElementPositioningStrategy( + LightTreePositioningStrategies.FUN_INTERFACE_ABSTRACT_PROPERTY, + PositioningStrategies.FUN_INTERFACE_ABSTRACT_PROPERTY + ) + val COMPANION_OBJECT = SourceElementPositioningStrategy( LightTreePositioningStrategies.COMPANION_OBJECT, PositioningStrategies.COMPANION_OBJECT @@ -103,6 +108,17 @@ object SourceElementPositioningStrategies { PositioningStrategies.INNER_MODIFIER ) + val FUN_MODIFIER = SourceElementPositioningStrategy( + LightTreePositioningStrategies.FUN_MODIFIER, + PositioningStrategies.FUN_MODIFIER + ) + + val SUSPEND_MODIFIER = SourceElementPositioningStrategy( + LightTreePositioningStrategies.SUSPEND_MODIFIER, + PositioningStrategies.SUSPEND_MODIFIER + ) + + val OPERATOR = SourceElementPositioningStrategy( LightTreePositioningStrategies.OPERATOR, PositioningStrategies.OPERATOR diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt index e6c233e5b80..c546ed99cfe 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt @@ -78,11 +78,12 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirDataClassPrimaryConstructorChecker, FirPrimaryConstructorSuperTypeChecker, FirTypeParametersInObjectChecker, - FirMemberFunctionsChecker, - FirMemberPropertiesChecker, - FirNestedClassChecker, - FirInlineClassDeclarationChecker, - ) + FirFunInterfaceDeclarationChecker, + FirMemberFunctionsChecker, + FirMemberPropertiesChecker, + FirNestedClassChecker, + FirInlineClassDeclarationChecker, + ) override val constructorCheckers: Set get() = setOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index 24de0c82722..1db9becbb87 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -370,6 +370,12 @@ object PositioningStrategies { @JvmField val CONST_MODIFIER: PositioningStrategy = modifierSetPosition(KtTokens.CONST_KEYWORD) + @JvmField + val FUN_MODIFIER: PositioningStrategy = modifierSetPosition(KtTokens.FUN_KEYWORD) + + @JvmField + val SUSPEND_MODIFIER: PositioningStrategy = modifierSetPosition(KtTokens.SUSPEND_KEYWORD) + @JvmField val FOR_REDECLARATION: PositioningStrategy = object : PositioningStrategy() { override fun mark(element: PsiElement): List { @@ -777,6 +783,17 @@ object PositioningStrategies { } } + @JvmField + val FUN_INTERFACE_ABSTRACT_PROPERTY: PositioningStrategy = object : PositioningStrategy() { + override fun mark(element: KtDeclaration): List { + return when (element) { + is KtClass -> FUN_MODIFIER.mark(element) + is KtProperty -> markElement(element.valOrVarKeyword) + else -> error("Expect interface or property, but was " + element.getElementTextWithContext()) + } + } + } + val REFERENCE_BY_QUALIFIED: PositioningStrategy = FindReferencePositioningStrategy(false) val REFERENCED_NAME_BY_QUALIFIED: PositioningStrategy = FindReferencePositioningStrategy(true) diff --git a/compiler/testData/diagnostics/tests/funInterface/funInterfaceDeclarationCheck.fir.kt b/compiler/testData/diagnostics/tests/funInterface/funInterfaceDeclarationCheck.fir.kt index ea025258bfd..f9ca9fce267 100644 --- a/compiler/testData/diagnostics/tests/funInterface/funInterfaceDeclarationCheck.fir.kt +++ b/compiler/testData/diagnostics/tests/funInterface/funInterfaceDeclarationCheck.fir.kt @@ -4,13 +4,13 @@ fun interface Good { fun invoke() } -fun interface Foo1 +fun interface Foo1 -fun interface Foo2 { +fun interface Foo2 { } -fun interface Foo3 { +fun interface Foo3 { fun foo() fun bar() } @@ -19,7 +19,7 @@ interface BaseWithSAM { fun base() } -fun interface Foo4 : BaseWithSAM { +fun interface Foo4 : BaseWithSAM { fun oneMore() } @@ -37,17 +37,17 @@ fun interface Foo4WithBaseDefault : BaseWithDefault { fun interface GoodWithBase : BaseWithSAM -fun interface Foo5 { - val prop: Int +fun interface Foo5 { + val prop: Int } fun interface Foo6 { fun foo() - val prop: Int + val prop: Int } fun interface Foo7 : BaseWithSAM { - val prop: Int + val prop: Int } fun interface GoodWithPropAndBase : BaseWithSAM { @@ -55,7 +55,7 @@ fun interface GoodWithPropAndBase : BaseWithSAM { } fun interface Foo8 { - fun invoke(x: T) + fun <T> invoke(x: T) } fun interface GoodGeneric { @@ -63,7 +63,7 @@ fun interface GoodGeneric { } interface BaseWithGeneric { - fun invoke(x: T) + fun <T> invoke(x: T) } fun interface Foo9 : BaseWithGeneric @@ -75,7 +75,7 @@ fun interface GoodSuspend { } class WithNestedFun { - fun interface NestedSimple + fun interface NestedSimple fun interface GoodFun { fun invoke() @@ -93,11 +93,11 @@ fun local() { } fun interface WithDefaultValue { - fun invoke(s: String = "") + fun invoke(s: String = "") } interface BaseWithDefaultValue { - fun invoke(s: String = "") + fun invoke(s: String = "") } fun interface DeriveDefault : BaseWithDefaultValue diff --git a/compiler/testData/diagnostics/tests/funInterface/resolveFunInterfaceWithoutMainMethod.fir.kt b/compiler/testData/diagnostics/tests/funInterface/resolveFunInterfaceWithoutMainMethod.fir.kt index cec3a4354d4..55da4c636f0 100644 --- a/compiler/testData/diagnostics/tests/funInterface/resolveFunInterfaceWithoutMainMethod.fir.kt +++ b/compiler/testData/diagnostics/tests/funInterface/resolveFunInterfaceWithoutMainMethod.fir.kt @@ -1,4 +1,4 @@ -fun interface IsolatedFunFace { +fun interface IsolatedFunFace { } typealias FunAlias = IsolatedFunFace @@ -9,4 +9,4 @@ fun callIsolatedFunFace() { referIsolatedFunFace(IsolatedFunFace {}) referIsolatedFunFace(FunAlias {}) referIsolatedFunFace({}) -} \ No newline at end of file +} diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index e511c3370f5..f59b53bd7ea 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -1413,6 +1413,36 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.FUN_INTERFACE_WRONG_COUNT_OF_ABSTRACT_MEMBERS) { firDiagnostic -> + FunInterfaceWrongCountOfAbstractMembersImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.FUN_INTERFACE_CANNOT_HAVE_ABSTRACT_PROPERTIES) { firDiagnostic -> + FunInterfaceCannotHaveAbstractPropertiesImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_TYPE_PARAMETERS) { firDiagnostic -> + FunInterfaceAbstractMethodWithTypeParametersImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.FUN_INTERFACE_ABSTRACT_METHOD_WITH_DEFAULT_VALUE) { firDiagnostic -> + FunInterfaceAbstractMethodWithDefaultValueImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } + add(FirErrors.FUN_INTERFACE_WITH_SUSPEND_FUNCTION) { firDiagnostic -> + FunInterfaceWithSuspendFunctionImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS) { firDiagnostic -> AbstractPropertyInNonAbstractClassImpl( firSymbolBuilder.buildSymbol(firDiagnostic.a as FirDeclaration), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 59e0f8f7e8d..28ed97c65b2 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -998,6 +998,26 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = FunInterfaceConstructorReference::class } + abstract class FunInterfaceWrongCountOfAbstractMembers : KtFirDiagnostic() { + override val diagnosticClass get() = FunInterfaceWrongCountOfAbstractMembers::class + } + + abstract class FunInterfaceCannotHaveAbstractProperties : KtFirDiagnostic() { + override val diagnosticClass get() = FunInterfaceCannotHaveAbstractProperties::class + } + + abstract class FunInterfaceAbstractMethodWithTypeParameters : KtFirDiagnostic() { + override val diagnosticClass get() = FunInterfaceAbstractMethodWithTypeParameters::class + } + + abstract class FunInterfaceAbstractMethodWithDefaultValue : KtFirDiagnostic() { + override val diagnosticClass get() = FunInterfaceAbstractMethodWithDefaultValue::class + } + + abstract class FunInterfaceWithSuspendFunction : KtFirDiagnostic() { + override val diagnosticClass get() = FunInterfaceWithSuspendFunction::class + } + abstract class AbstractPropertyInNonAbstractClass : KtFirDiagnostic() { override val diagnosticClass get() = AbstractPropertyInNonAbstractClass::class abstract val property: KtSymbol diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 5b64f6869f7..724e8585083 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -1608,6 +1608,41 @@ internal class FunInterfaceConstructorReferenceImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class FunInterfaceWrongCountOfAbstractMembersImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.FunInterfaceWrongCountOfAbstractMembers(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class FunInterfaceCannotHaveAbstractPropertiesImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.FunInterfaceCannotHaveAbstractProperties(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class FunInterfaceAbstractMethodWithTypeParametersImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.FunInterfaceAbstractMethodWithTypeParameters(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class FunInterfaceAbstractMethodWithDefaultValueImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.FunInterfaceAbstractMethodWithDefaultValue(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + +internal class FunInterfaceWithSuspendFunctionImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.FunInterfaceWithSuspendFunction(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class AbstractPropertyInNonAbstractClassImpl( override val property: KtSymbol, override val containingClass: KtSymbol,