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 caac66cd984..231451aa5d8 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 @@ -1188,6 +1188,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val REIFIED_TYPE_PARAMETER_IN_OVERRIDE by error(PositioningStrategy.REIFIED_MODIFIER) val INLINE_PROPERTY_WITH_BACKING_FIELD by error(PositioningStrategy.DECLARATION_SIGNATURE) + + val ILLEGAL_INLINE_PARAMETER_MODIFIER by error(PositioningStrategy.INLINE_PARAMETER_MODIFIER) } val IMPORTS by object : DiagnosticGroup("Imports") { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt index 8d5228bbd63..da61c49038b 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt @@ -99,6 +99,7 @@ enum class PositioningStrategy(private val strategy: String? = null) { INCOMPATIBLE_DECLARATION, ACTUAL_DECLARATION_NAME, UNREACHABLE_CODE, + INLINE_PARAMETER_MODIFIER, ; 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 4652144351e..27a4c7cb66d 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 @@ -614,6 +614,7 @@ object FirErrors { val INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE by error2() val REIFIED_TYPE_PARAMETER_IN_OVERRIDE by error0(SourceElementPositioningStrategies.REIFIED_MODIFIER) val INLINE_PROPERTY_WITH_BACKING_FIELD by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val ILLEGAL_INLINE_PARAMETER_MODIFIER by error0(SourceElementPositioningStrategies.INLINE_PARAMETER_MODIFIER) // Imports val CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON by error1(SourceElementPositioningStrategies.IMPORT_LAST_NAME) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt index b3e184ee703..efa23623d76 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirInlineDeclarationChecker.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.context.PersistentCheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.getModifier import org.jetbrains.kotlin.fir.analysis.checkers.isInlineOnly import org.jetbrains.kotlin.fir.analysis.checkers.unsubstitutedScope import org.jetbrains.kotlin.fir.analysis.checkers.util.checkChildrenWithCustomVisitor @@ -38,7 +39,10 @@ import org.jetbrains.kotlin.util.OperatorNameConventions object FirInlineDeclarationChecker : FirFunctionChecker() { override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) { - if (!declaration.isInline) return + if (!declaration.isInline) { + checkParametersInNotInline(declaration, context, reporter) + return + } // local inline functions are prohibited if (declaration.isLocalMember) { reporter.reportOn(declaration.source, FirErrors.NOT_YET_SUPPORTED_IN_INLINE, "Local inline functions", context) @@ -341,12 +345,18 @@ object FirInlineDeclarationChecker : FirFunctionChecker() { reporter: DiagnosticReporter ) { for (param in function.valueParameters) { - if (param.isNoinline) continue - val coneType = param.returnTypeRef.coneType val isFunctionalType = coneType.isFunctionalType(context.session) + val isSuspendFunctionalType = coneType.isSuspendFunctionType(context.session) val defaultValue = param.defaultValue - if (function.isSuspend && defaultValue != null && coneType.isSuspendFunctionType(context.session)) { + + if (!(isFunctionalType || isSuspendFunctionalType) && (param.isNoinline || param.isCrossinline)) { + reporter.reportOn(param.source, FirErrors.ILLEGAL_INLINE_PARAMETER_MODIFIER, context) + } + + if (param.isNoinline) continue + + if (function.isSuspend && defaultValue != null && isSuspendFunctionalType) { reporter.reportOn( param.source, FirErrors.NOT_YET_SUPPORTED_IN_INLINE, @@ -403,6 +413,14 @@ object FirInlineDeclarationChecker : FirFunctionChecker() { } } + private fun checkParametersInNotInline(function: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) { + for (param in function.valueParameters) { + if (param.isNoinline || param.isCrossinline) { + reporter.reportOn(param.source, FirErrors.ILLEGAL_INLINE_PARAMETER_MODIFIER, context) + } + } + } + private fun FirCallableDeclaration.getOverriddenSymbols(context: CheckerContext): List> { if (!this.isOverride) return emptyList() val classSymbol = this.containingClass()?.toSymbol(context.session) as? FirClassSymbol<*> ?: return emptyList() 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 221972f7de8..4620428df79 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 @@ -190,6 +190,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GENERIC_THROWABLE 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 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXPRESSION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_INLINE_PARAMETER_MODIFIER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_SELECTOR @@ -1515,6 +1516,8 @@ class FirDefaultErrorMessages { map.put(SUPER_CALL_FROM_PUBLIC_INLINE, "Accessing super members from public-API inline function is deprecated", SYMBOL) + map.put(ILLEGAL_INLINE_PARAMETER_MODIFIER, "Modifier is allowed only for function parameters of an inline function") + //imports map.put( CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON, 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 fa146b0a646..1f9b31fa3a8 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 @@ -358,6 +358,9 @@ object LightTreePositioningStrategies { val DATA_MODIFIER: LightTreePositioningStrategy = ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.DATA_KEYWORD)) + val INLINE_PARAMETER_MODIFIER: LightTreePositioningStrategy = + ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.NOINLINE_KEYWORD, KtTokens.CROSSINLINE_KEYWORD)) + val OPERATOR: LightTreePositioningStrategy = object : LightTreePositioningStrategy() { override fun mark( node: LighterASTNode, 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 c273de44a81..9ba5f9e3ac4 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 @@ -286,4 +286,9 @@ object SourceElementPositioningStrategies { LightTreePositioningStrategies.NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT, PositioningStrategies.NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT ) + + val INLINE_PARAMETER_MODIFIER = SourceElementPositioningStrategy( + LightTreePositioningStrategies.INLINE_PARAMETER_MODIFIER, + PositioningStrategies.INLINE_PARAMETER_MODIFIER + ) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index caf16c2e89a..ef0ca0fe38a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -496,6 +496,10 @@ object PositioningStrategies { val INNER_MODIFIER: PositioningStrategy = ModifierSetBasedPositioningStrategy(TokenSet.create(KtTokens.INNER_KEYWORD)) + @JvmField + val INLINE_PARAMETER_MODIFIER: PositioningStrategy = + ModifierSetBasedPositioningStrategy(TokenSet.create(KtTokens.NOINLINE_KEYWORD, KtTokens.CROSSINLINE_KEYWORD)) + @JvmField val VARIANCE_IN_PROJECTION: PositioningStrategy = object : PositioningStrategy() { override fun mark(element: KtTypeProjection): List { diff --git a/compiler/testData/diagnostics/tests/modifiers/inlineParameters.fir.kt b/compiler/testData/diagnostics/tests/modifiers/inlineParameters.fir.kt deleted file mode 100644 index 1548e608688..00000000000 --- a/compiler/testData/diagnostics/tests/modifiers/inlineParameters.fir.kt +++ /dev/null @@ -1,20 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER - -inline fun foo(noinline x: Int) {} - -inline fun bar(y: Int, crossinline x: String) {} - -fun gav(noinline x: (Int) -> Unit, crossinline y: (String) -> Int) {} - -inline fun correct(noinline x: (Int) -> Unit, crossinline y: (String) -> Int) {} - -inline fun incompatible(noinline crossinline x: () -> String) {} - -class FunctionSubtype : () -> Unit { - override fun invoke() {} -} - -inline fun functionSubtype( - noinline f: FunctionSubtype, - crossinline g: FunctionSubtype -) { } diff --git a/compiler/testData/diagnostics/tests/modifiers/inlineParameters.kt b/compiler/testData/diagnostics/tests/modifiers/inlineParameters.kt index b12b65208b1..a783b11d611 100644 --- a/compiler/testData/diagnostics/tests/modifiers/inlineParameters.kt +++ b/compiler/testData/diagnostics/tests/modifiers/inlineParameters.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER inline fun foo(noinline x: Int) {} 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 aea8b5ecb6e..9646043ba81 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 @@ -3205,6 +3205,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.ILLEGAL_INLINE_PARAMETER_MODIFIER) { firDiagnostic -> + IllegalInlineParameterModifierImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON) { firDiagnostic -> CannotAllUnderImportFromSingletonImpl( firDiagnostic.a, 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 03b25ca6b1a..623fc9d6dbc 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 @@ -2236,6 +2236,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = InlinePropertyWithBackingField::class } + abstract class IllegalInlineParameterModifier : KtFirDiagnostic() { + override val diagnosticClass get() = IllegalInlineParameterModifier::class + } + abstract class CannotAllUnderImportFromSingleton : KtFirDiagnostic() { override val diagnosticClass get() = CannotAllUnderImportFromSingleton::class abstract val objectName: Name 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 ee1ad62e58e..b77cf3c6d34 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 @@ -3611,6 +3611,13 @@ internal class InlinePropertyWithBackingFieldImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class IllegalInlineParameterModifierImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.IllegalInlineParameterModifier(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class CannotAllUnderImportFromSingletonImpl( override val objectName: Name, firDiagnostic: FirPsiDiagnostic,