Forbid ExtensionFunctionType on functional types without parameters
#KT-43527 Fixed
This commit is contained in:
+6
@@ -945,6 +945,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.WRONG_EXTENSION_FUNCTION_TYPE) { firDiagnostic ->
|
||||
WrongExtensionFunctionTypeImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.OPT_IN_USAGE) { firDiagnostic ->
|
||||
OptInUsageImpl(
|
||||
firDiagnostic.a,
|
||||
|
||||
+4
@@ -680,6 +680,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = NotAClass::class
|
||||
}
|
||||
|
||||
abstract class WrongExtensionFunctionType : KtFirDiagnostic<KtAnnotationEntry>() {
|
||||
override val diagnosticClass get() = WrongExtensionFunctionType::class
|
||||
}
|
||||
|
||||
abstract class OptInUsage : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = OptInUsage::class
|
||||
abstract val optInMarkerFqName: FqName
|
||||
|
||||
+5
@@ -816,6 +816,11 @@ internal class NotAClassImpl(
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.NotAClass(), KtAbstractFirDiagnostic<PsiElement>
|
||||
|
||||
internal class WrongExtensionFunctionTypeImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.WrongExtensionFunctionType(), KtAbstractFirDiagnostic<KtAnnotationEntry>
|
||||
|
||||
internal class OptInUsageImpl(
|
||||
override val optInMarkerFqName: FqName,
|
||||
override val message: String,
|
||||
|
||||
+1
@@ -287,6 +287,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val REPEATED_ANNOTATION by error<KtAnnotationEntry>()
|
||||
val REPEATED_ANNOTATION_WARNING by warning<KtAnnotationEntry>()
|
||||
val NOT_A_CLASS by error<PsiElement>()
|
||||
val WRONG_EXTENSION_FUNCTION_TYPE by error<KtAnnotationEntry>()
|
||||
}
|
||||
|
||||
val OPT_IN by object : DiagnosticGroup("OptIn") {
|
||||
|
||||
@@ -253,6 +253,7 @@ object FirErrors {
|
||||
val REPEATED_ANNOTATION by error0<KtAnnotationEntry>()
|
||||
val REPEATED_ANNOTATION_WARNING by warning0<KtAnnotationEntry>()
|
||||
val NOT_A_CLASS by error0<PsiElement>()
|
||||
val WRONG_EXTENSION_FUNCTION_TYPE by error0<KtAnnotationEntry>()
|
||||
|
||||
// OptIn
|
||||
val OPT_IN_USAGE by warning2<PsiElement, FqName, String>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
+8
@@ -12,8 +12,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
|
||||
import org.jetbrains.kotlin.fir.expressions.classId
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
object FirTypeAnnotationChecker : FirTypeRefChecker() {
|
||||
override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
@@ -29,6 +32,11 @@ object FirTypeAnnotationChecker : FirTypeRefChecker() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (annotation.classId == StandardClassIds.Annotations.ExtensionFunctionType) {
|
||||
if (typeRef.type.isBuiltinFunctionalType(context.session) && typeRef.type.typeArguments.size <= 1) {
|
||||
reporter.reportOn(annotation.source, FirErrors.WRONG_EXTENSION_FUNCTION_TYPE, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -561,6 +561,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAR_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VIRTUAL_MEMBER_HIDDEN
|
||||
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_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
|
||||
@@ -853,6 +854,7 @@ 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")
|
||||
|
||||
// Exposed visibility group // #
|
||||
map.put(
|
||||
|
||||
@@ -278,6 +278,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION_WARNING = DiagnosticFactory0.create(WARNING);
|
||||
DiagnosticFactory0<KtAnnotationEntry> NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> WRONG_EXTENSION_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
// Annotations
|
||||
|
||||
|
||||
+1
@@ -146,6 +146,7 @@ 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(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);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.isFunctionOrKFunctionTypeWithAnySuspendability
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.*
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
@@ -19,11 +20,13 @@ import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
|
||||
import org.jetbrains.kotlin.resolve.constants.ArrayValue
|
||||
import org.jetbrains.kotlin.resolve.constants.EnumValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getAnnotationRetention
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotatedWithKotlinRepeatable
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
@@ -163,9 +166,9 @@ class AnnotationChecker(
|
||||
checkWithoutLanguageFeature: Boolean = false
|
||||
) {
|
||||
val shouldRunCheck = isSuperType || shouldCheckReferenceItself
|
||||
if (shouldRunCheck) {
|
||||
for (entry in reference.annotationEntries) {
|
||||
val descriptor = trace.get(BindingContext.ANNOTATION, entry)
|
||||
for (entry in reference.annotationEntries) {
|
||||
val descriptor = trace.get(BindingContext.ANNOTATION, entry)
|
||||
if (shouldRunCheck) {
|
||||
if (descriptor is LazyAnnotationDescriptor) {
|
||||
/*
|
||||
* There are no users of type annotations until backend, so if there are errors
|
||||
@@ -181,6 +184,12 @@ class AnnotationChecker(
|
||||
checkAnnotationEntry(entry, actualTargets, trace)
|
||||
}
|
||||
}
|
||||
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 typeArguments = reference.typeElement?.typeArgumentsAsTypes ?: return
|
||||
for (typeArgument in typeArguments) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// WITH_STDLIB
|
||||
// This test checks that annotations on extension function types are preserved. See the corresponding .txt file
|
||||
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class ann
|
||||
|
||||
interface Some {
|
||||
fun f1(): String.() -> Int
|
||||
fun f2(): @ExtensionFunctionType() (String.() -> Int)
|
||||
fun f3(): @ann String.() -> Int
|
||||
fun f4(): @ExtensionFunctionType @ann() (String.() -> Int)
|
||||
|
||||
fun f5(): <!WRONG_EXTENSION_FUNCTION_TYPE!>@ExtensionFunctionType<!> () -> Int
|
||||
|
||||
fun f6(x: <!WRONG_EXTENSION_FUNCTION_TYPE!>@ExtensionFunctionType<!> () -> Int) {
|
||||
<!OVERLOAD_RESOLUTION_AMBIGUITY!>println<!>(x <!UNRESOLVED_REFERENCE!>+<!> 2)
|
||||
}
|
||||
|
||||
fun f7(x: <!WRONG_EXTENSION_FUNCTION_TYPE!>@ExtensionFunctionType<!> Function0<Int>)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
// This test checks that annotations on extension function types are preserved. See the corresponding .txt file
|
||||
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
@@ -9,4 +9,12 @@ interface Some {
|
||||
fun f2(): @ExtensionFunctionType() (String.() -> Int)
|
||||
fun f3(): @ann String.() -> Int
|
||||
fun f4(): @ExtensionFunctionType @ann() (String.() -> Int)
|
||||
|
||||
fun f5(): <!WRONG_EXTENSION_FUNCTION_TYPE!>@ExtensionFunctionType<!> () -> Int
|
||||
|
||||
fun f6(x: <!WRONG_EXTENSION_FUNCTION_TYPE!>@ExtensionFunctionType<!> () -> Int) {
|
||||
println(x <!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>+<!> 2)
|
||||
}
|
||||
|
||||
fun f7(x: <!WRONG_EXTENSION_FUNCTION_TYPE!>@ExtensionFunctionType<!> Function0<Int>)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ public interface Some {
|
||||
public abstract fun f2(): kotlin.String.() -> kotlin.Int
|
||||
public abstract fun f3(): @ann() (kotlin.String.() -> kotlin.Int)
|
||||
public abstract fun f4(): @ann() (kotlin.String.() -> kotlin.Int)
|
||||
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 open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@@ -373,17 +373,21 @@ internal class DescriptorRendererImpl(
|
||||
|
||||
append("(")
|
||||
|
||||
val parameterTypes = type.getValueParameterTypesFromFunctionType()
|
||||
for ((index, typeProjection) in parameterTypes.withIndex()) {
|
||||
if (index > 0) append(", ")
|
||||
if (type.isBuiltinExtensionFunctionalType && type.arguments.size <= 1) {
|
||||
append("???")
|
||||
} else {
|
||||
val parameterTypes = type.getValueParameterTypesFromFunctionType()
|
||||
for ((index, typeProjection) in parameterTypes.withIndex()) {
|
||||
if (index > 0) append(", ")
|
||||
|
||||
val name = if (parameterNamesInFunctionalTypes) typeProjection.type.extractParameterNameFromFunctionTypeArgument() else null
|
||||
if (name != null) {
|
||||
append(renderName(name, false))
|
||||
append(": ")
|
||||
val name = if (parameterNamesInFunctionalTypes) typeProjection.type.extractParameterNameFromFunctionTypeArgument() else null
|
||||
if (name != null) {
|
||||
append(renderName(name, false))
|
||||
append(": ")
|
||||
}
|
||||
|
||||
append(renderTypeProjection(typeProjection))
|
||||
}
|
||||
|
||||
append(renderTypeProjection(typeProjection))
|
||||
}
|
||||
|
||||
append(") ").append(arrow()).append(" ")
|
||||
|
||||
Reference in New Issue
Block a user