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 adbbf059864..d37e934e2fc 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 @@ -951,6 +951,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.WRONG_EXTENSION_FUNCTION_TYPE_WARNING) { firDiagnostic -> + WrongExtensionFunctionTypeWarningImpl( + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.OPT_IN_USAGE) { firDiagnostic -> OptInUsageImpl( firDiagnostic.a, 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 ae9a3fe5295..fd4b2fd5428 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 @@ -684,6 +684,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = WrongExtensionFunctionType::class } + abstract class WrongExtensionFunctionTypeWarning : KtFirDiagnostic() { + override val diagnosticClass get() = WrongExtensionFunctionTypeWarning::class + } + abstract class OptInUsage : KtFirDiagnostic() { override val diagnosticClass get() = OptInUsage::class abstract val optInMarkerFqName: FqName 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 f9f84e6b27c..77e4b6847cb 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 @@ -821,6 +821,11 @@ internal class WrongExtensionFunctionTypeImpl( override val token: ValidityToken, ) : KtFirDiagnostic.WrongExtensionFunctionType(), KtAbstractFirDiagnostic +internal class WrongExtensionFunctionTypeWarningImpl( + override val firDiagnostic: KtPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.WrongExtensionFunctionTypeWarning(), KtAbstractFirDiagnostic + internal class OptInUsageImpl( override val optInMarkerFqName: FqName, override val message: String, 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 2ee92bb19b7..4d0aeb9c067 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 @@ -288,6 +288,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val REPEATED_ANNOTATION_WARNING by warning() val NOT_A_CLASS by error() val WRONG_EXTENSION_FUNCTION_TYPE by error() + val WRONG_EXTENSION_FUNCTION_TYPE_WARNING by warning() } val OPT_IN by object : DiagnosticGroup("OptIn") { 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 8f0c35f874c..4389b7a4cf5 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 @@ -254,6 +254,7 @@ object FirErrors { val REPEATED_ANNOTATION_WARNING by warning0() val NOT_A_CLASS by error0() val WRONG_EXTENSION_FUNCTION_TYPE by error0() + val WRONG_EXTENSION_FUNCTION_TYPE_WARNING by warning0() // OptIn val OPT_IN_USAGE by warning2(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeAnnotationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeAnnotationChecker.kt index c0b64a08c9f..801bb649bd6 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeAnnotationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirTypeAnnotationChecker.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.type +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.getAllowedAnnotationTargets @@ -33,7 +34,14 @@ object FirTypeAnnotationChecker : FirTypeRefChecker() { } } if (annotation.classId == StandardClassIds.Annotations.ExtensionFunctionType) { - if (typeRef.type.isBuiltinFunctionalType(context.session) && typeRef.type.typeArguments.size <= 1) { + if (!typeRef.type.isBuiltinFunctionalType(context.session)) { + if (context.languageVersionSettings.supportsFeature(LanguageFeature.ForbidExtensionFunctionTypeOnNonFunctionTypes)) { + reporter.reportOn(annotation.source, FirErrors.WRONG_EXTENSION_FUNCTION_TYPE, context) + } else { + reporter.reportOn(annotation.source, FirErrors.WRONG_EXTENSION_FUNCTION_TYPE_WARNING, context) + } + + } else if (typeRef.type.typeArguments.size <= 1) { reporter.reportOn(annotation.source, FirErrors.WRONG_EXTENSION_FUNCTION_TYPE, 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 4f48eba6f37..0b716812949 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 @@ -562,6 +562,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VIRTUAL_MEMBER_HI import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_EXTENSION_FUNCTION_TYPE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_EXTENSION_FUNCTION_TYPE_WARNING import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_GETTER_RETURN_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_INVOCATION_KIND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_LONG_SUFFIX @@ -854,7 +855,14 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { "Opt-in requirement marker annotation on override makes no sense without the same marker on base declaration" ) map.put(NOT_A_CLASS, "Not a class") - map.put(WRONG_EXTENSION_FUNCTION_TYPE, "ExtensionFunctionType is forbidden on a function type without parameters") + map.put( + WRONG_EXTENSION_FUNCTION_TYPE, + "ExtensionFunctionType is forbidden on a function type without parameters or on a non-function type" + ) + map.put( + WRONG_EXTENSION_FUNCTION_TYPE_WARNING, + "ExtensionFunctionType makes no sense on a non-function type. It will be an error in a future release." + ) // Exposed visibility group // # map.put( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 363f99f51d2..2cd96cc9761 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -279,6 +279,7 @@ public interface Errors { DiagnosticFactory0 REPEATED_ANNOTATION_WARNING = DiagnosticFactory0.create(WARNING); DiagnosticFactory0 NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 WRONG_EXTENSION_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 WRONG_EXTENSION_FUNCTION_TYPE_WARNING = DiagnosticFactory0.create(WARNING); // Annotations diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 0f5d2cc8df3..f942d3ccbd4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -146,7 +146,8 @@ public class DefaultErrorMessages { MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable"); MAP.put(REPEATED_ANNOTATION_WARNING, "This annotation is not repeatable"); MAP.put(NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION, "The lambda expression here is an inlined argument so this annotation cannot be stored anywhere"); - MAP.put(WRONG_EXTENSION_FUNCTION_TYPE, "ExtensionFunctionType is forbidden on a function type without parameters"); + MAP.put(WRONG_EXTENSION_FUNCTION_TYPE, "ExtensionFunctionType is forbidden on a function type without parameters or on a non-function type"); + MAP.put(WRONG_EXTENSION_FUNCTION_TYPE_WARNING, "ExtensionFunctionType makes no sense on a non-function type. It will be an error in a future release."); MAP.put(INAPPLICABLE_TARGET_ON_PROPERTY, "''@{0}:'' annotations could be applied only to property declarations", TO_STRING); MAP.put(INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE, "''@{0}:'' annotations could be applied only to mutable properties", TO_STRING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt index 346a173ec87..9316cb277c3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt @@ -185,9 +185,17 @@ class AnnotationChecker( } } if (descriptor?.annotationClass?.classId == StandardClassIds.Annotations.ExtensionFunctionType) { - val type = trace[BindingContext.TYPE, reference] - if (type != null && type.isFunctionOrKFunctionTypeWithAnySuspendability && type.arguments.size <= 1) { - trace.report(Errors.WRONG_EXTENSION_FUNCTION_TYPE.on(entry)) + val type = trace[BindingContext.TYPE, reference] ?: trace[BindingContext.ABBREVIATED_TYPE, reference] + if (type != null) { + if (!type.isFunctionOrKFunctionTypeWithAnySuspendability) { + if (languageVersionSettings.supportsFeature(ForbidExtensionFunctionTypeOnNonFunctionTypes)) { + trace.report(Errors.WRONG_EXTENSION_FUNCTION_TYPE.on(entry)) + } else { + trace.report(Errors.WRONG_EXTENSION_FUNCTION_TYPE_WARNING.on(entry)) + } + } else if (type.arguments.size <= 1) { + trace.report(Errors.WRONG_EXTENSION_FUNCTION_TYPE.on(entry)) + } } } } diff --git a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.fir.kt b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.fir.kt index 658970e217d..f048c268769 100644 --- a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.fir.kt +++ b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.fir.kt @@ -6,7 +6,7 @@ fun foo(a: (String) -> Unit) { interface A : (String) -> Unit {} -fun foo(a: @ExtensionFunctionType A) { +fun foo(a: @ExtensionFunctionType A) { // @Extension annotation on an unrelated type shouldn't have any effect on this diagnostic. // Only kotlin.Function{n} type annotated with @Extension should "".a() diff --git a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt index 22b2715d38f..9d4148c2160 100644 --- a/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt +++ b/compiler/testData/diagnostics/tests/FreeFunctionCalledAsExtension.kt @@ -6,7 +6,7 @@ fun foo(a: (String) -> Unit) { interface A : (String) -> Unit {} -fun foo(a: @ExtensionFunctionType A) { +fun foo(a: @ExtensionFunctionType A) { // @Extension annotation on an unrelated type shouldn't have any effect on this diagnostic. // Only kotlin.Function{n} type annotated with @Extension should "".a() diff --git a/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.fir.kt b/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.fir.kt index 033af7e4477..51719570dac 100644 --- a/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.fir.kt +++ b/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.fir.kt @@ -1,4 +1,5 @@ // WITH_STDLIB +// !LANGUAGE: +ForbidExtensionFunctionTypeOnNonFunctionTypes // This test checks that annotations on extension function types are preserved. See the corresponding .txt file @Target(AnnotationTarget.TYPE) @@ -17,4 +18,6 @@ interface Some { } fun f7(x: @ExtensionFunctionType Function0) + + fun f8(x: @ExtensionFunctionType Int) } diff --git a/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.kt b/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.kt index ca26db3e682..617734c71a6 100644 --- a/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.kt +++ b/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.kt @@ -1,4 +1,5 @@ // WITH_STDLIB +// !LANGUAGE: +ForbidExtensionFunctionTypeOnNonFunctionTypes // This test checks that annotations on extension function types are preserved. See the corresponding .txt file @Target(AnnotationTarget.TYPE) @@ -17,4 +18,6 @@ interface Some { } fun f7(x: @ExtensionFunctionType Function0) + + fun f8(x: @ExtensionFunctionType Int) } diff --git a/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.txt b/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.txt index f80fd2e937b..45a7e75d9c6 100644 --- a/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.txt +++ b/compiler/testData/diagnostics/tests/annotations/extensionFunctionType.txt @@ -9,6 +9,7 @@ public interface Some { public abstract fun f5(): kotlin.Int.(???) -> kotlin.Int public open fun f6(/*0*/ x: kotlin.Int.(???) -> kotlin.Int): kotlin.Unit public abstract fun f7(/*0*/ x: kotlin.Int.(???) -> kotlin.Int): kotlin.Unit + public abstract fun f8(/*0*/ x: @kotlin.ExtensionFunctionType kotlin.Int): 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/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.kt b/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.kt index 1b617caffd1..6c666b59c25 100644 --- a/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.kt +++ b/compiler/testData/diagnostics/tests/typealias/typealiasRhsAnnotations.kt @@ -1,4 +1,5 @@ // FIR_IDENTICAL +// !LANGUAGE: -ForbidExtensionFunctionTypeOnNonFunctionTypes @Target(AnnotationTarget.TYPE) annotation class Ann1 @@ -9,8 +10,7 @@ typealias Alias1 = @Ann1 String typealias Alias2 = @Ann2 Alias1 fun test1(a: Alias2) = a -// NB @ExtensionFunctionType on non-functional type is not an error -typealias Alias3 = @ExtensionFunctionType Alias1 +typealias Alias3 = @ExtensionFunctionType Alias1 fun test2(a: Alias3) = a typealias LA1 = List<@Ann2 Alias1> diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 409db41e497..f29f1ac637b 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -263,6 +263,7 @@ enum class LanguageFeature( ProhibitConstructorCallOnFunctionalSupertype(KOTLIN_1_9, kind = BUG_FIX), // KT-46344 ProhibitArrayLiteralsInCompanionOfAnnotation(KOTLIN_1_9, kind = BUG_FIX), // KT-39041 ProhibitCyclesInAnnotations(KOTLIN_1_9, kind = BUG_FIX), // KT-49110 + ForbidExtensionFunctionTypeOnNonFunctionTypes(KOTLIN_1_9), // related to KT-43527 // Temporarily disabled, see KT-27084/KT-22379 SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX),