From 4e06814bc59ac41e75516efcb0b2df70b13ac426 Mon Sep 17 00:00:00 2001 From: Andrey Zinovyev Date: Tue, 20 Jul 2021 15:32:10 +0300 Subject: [PATCH] [FIR] Add NULLABLE_INLINE_PARAMETER diagnostic --- .../diagnostics/FirDiagnosticsList.kt | 5 +++ .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../FirInlineDeclarationChecker.kt | 33 ++++++++++++------- .../diagnostics/FirDefaultErrorMessages.kt | 8 +++++ .../diagnostics/tests/inline/kt19679.fir.kt | 4 --- .../diagnostics/tests/inline/kt19679.kt | 1 + .../tests/inline/nullableFunction.fir.kt | 21 ------------ .../tests/inline/nullableFunction.kt | 1 + .../diagnostics/KtFirDataClassConverters.kt | 8 +++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 6 ++++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 9 +++++ 11 files changed, 61 insertions(+), 36 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/inline/kt19679.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/inline/nullableFunction.fir.kt 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 7fb5a34da0c..3dc588b8bd7 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 @@ -1136,6 +1136,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val NOTHING_TO_INLINE by warning(PositioningStrategy.NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT) + val NULLABLE_INLINE_PARAMETER by error() { + parameter("parameter") + parameter("function") + } + val RECURSION_IN_INLINE by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { parameter("symbol") } 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 f94101271e0..1f6bfc1f17c 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 @@ -600,6 +600,7 @@ object FirErrors { val NON_LOCAL_RETURN_NOT_ALLOWED by error1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val NOT_YET_SUPPORTED_IN_INLINE by error1(SourceElementPositioningStrategies.NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT) val NOTHING_TO_INLINE by warning0(SourceElementPositioningStrategies.NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT) + val NULLABLE_INLINE_PARAMETER by error2>() val RECURSION_IN_INLINE by error1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val NON_PUBLIC_CALL_FROM_PUBLIC_INLINE by error2, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE by error2, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) 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 1b2b4e89a84..91900b1b200 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 @@ -338,17 +338,28 @@ object FirInlineDeclarationChecker : FirFunctionChecker() { private fun checkParameters(function: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) { if (function !is FirSimpleFunction) return - if (function.isSuspend) { - function.valueParameters - .filter { !it.isNoinline && it.defaultValue != null && it.returnTypeRef.coneType.isSuspendFunctionType(context.session) } - .forEach { param -> - reporter.reportOn( - param.source, - FirErrors.NOT_YET_SUPPORTED_IN_INLINE, - "Suspend functional parameters with default values", - context - ) - } + for (param in function.valueParameters) { + if (param.isNoinline) continue + + val coneType = param.returnTypeRef.coneType + if (function.isSuspend && param.defaultValue != null && coneType.isSuspendFunctionType(context.session)) { + reporter.reportOn( + param.source, + FirErrors.NOT_YET_SUPPORTED_IN_INLINE, + "Suspend functional parameters with default values", + context + ) + } + + if (coneType.isNullable && coneType.isFunctionalType(context.session)) { + reporter.reportOn( + param.source, + FirErrors.NULLABLE_INLINE_PARAMETER, + param.symbol, + function.symbol, + context + ) + } } //check for inherited default values 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 89f17c3d5d2..cd9a84125b3 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 @@ -288,6 +288,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_RETURN_IN_FUNC import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_SET_METHOD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_THIS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_VALUE_FOR_PARAMETER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_INLINE_PARAMETER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_SUPERTYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_TYPE_IN_CLASS_LITERAL_LHS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER @@ -1488,6 +1489,13 @@ class FirDefaultErrorMessages { NOTHING_TO_INLINE, "Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types" ) + map.put( + NULLABLE_INLINE_PARAMETER, + "Inline-parameter ''{0}'' of ''{1}'' must not be nullable. Add ''noinline'' modifier to the parameter declaration or make its type not nullable", + SYMBOL, + SYMBOL + ) + map.put(SUPER_CALL_FROM_PUBLIC_INLINE, "Accessing super members from public-API inline function is deprecated", SYMBOL) //imports diff --git a/compiler/testData/diagnostics/tests/inline/kt19679.fir.kt b/compiler/testData/diagnostics/tests/inline/kt19679.fir.kt deleted file mode 100644 index 8c58ee90d84..00000000000 --- a/compiler/testData/diagnostics/tests/inline/kt19679.fir.kt +++ /dev/null @@ -1,4 +0,0 @@ -inline fun test(s: () -> Unit, p: (() -> Unit)?) { - s() - p?.invoke() -} diff --git a/compiler/testData/diagnostics/tests/inline/kt19679.kt b/compiler/testData/diagnostics/tests/inline/kt19679.kt index 509269f7e1c..f0149d6d4a0 100644 --- a/compiler/testData/diagnostics/tests/inline/kt19679.kt +++ b/compiler/testData/diagnostics/tests/inline/kt19679.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL inline fun test(s: () -> Unit, p: (() -> Unit)?) { s() p?.invoke() diff --git a/compiler/testData/diagnostics/tests/inline/nullableFunction.fir.kt b/compiler/testData/diagnostics/tests/inline/nullableFunction.fir.kt deleted file mode 100644 index 030b66b226b..00000000000 --- a/compiler/testData/diagnostics/tests/inline/nullableFunction.fir.kt +++ /dev/null @@ -1,21 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -CONFLICTING_JVM_DECLARATIONS - -public inline fun Function1?.submit(action: ()->T) { - this?.invoke(11) -} - -public inline fun submit(action: Function1?, s: () -> Int) { - action?.invoke(10) -} - -public inline fun submitNoInline(noinline action: Function1?, s: () -> Int) { - action?.invoke(10) -} - -public inline fun Function1?.submit() { - -} - -public inline fun submit(action: Function1?) { - -} diff --git a/compiler/testData/diagnostics/tests/inline/nullableFunction.kt b/compiler/testData/diagnostics/tests/inline/nullableFunction.kt index 11638241e99..856bcf46ae3 100644 --- a/compiler/testData/diagnostics/tests/inline/nullableFunction.kt +++ b/compiler/testData/diagnostics/tests/inline/nullableFunction.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -CONFLICTING_JVM_DECLARATIONS public inline fun Function1?.submit(action: ()->T) { 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 4dcddf709e3..8f42514086d 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 @@ -3105,6 +3105,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.NULLABLE_INLINE_PARAMETER) { firDiagnostic -> + NullableInlineParameterImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a.fir), + firSymbolBuilder.buildSymbol(firDiagnostic.b.fir), + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.RECURSION_IN_INLINE) { firDiagnostic -> RecursionInInlineImpl( firSymbolBuilder.buildSymbol(firDiagnostic.a.fir), 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 b49cca11abd..c4b25e93d88 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 @@ -2164,6 +2164,12 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = NothingToInline::class } + abstract class NullableInlineParameter : KtFirDiagnostic() { + override val diagnosticClass get() = NullableInlineParameter::class + abstract val parameter: KtSymbol + abstract val function: KtSymbol + } + abstract class RecursionInInline : KtFirDiagnostic() { override val diagnosticClass get() = RecursionInInline::class abstract val symbol: 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 20a0a3a7ed2..c6388277e7b 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 @@ -3497,6 +3497,15 @@ internal class NothingToInlineImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class NullableInlineParameterImpl( + override val parameter: KtSymbol, + override val function: KtSymbol, + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.NullableInlineParameter(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class RecursionInInlineImpl( override val symbol: KtSymbol, firDiagnostic: FirPsiDiagnostic,