Forbid ExtensionFunctionType on functional types without parameters

#KT-43527 Fixed
This commit is contained in:
Mikhail Glukhikh
2022-01-11 16:42:35 +03:00
parent beb2957726
commit d0fa3eb1d3
14 changed files with 86 additions and 13 deletions
@@ -945,6 +945,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.WRONG_EXTENSION_FUNCTION_TYPE) { firDiagnostic ->
WrongExtensionFunctionTypeImpl(
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.OPT_IN_USAGE) { firDiagnostic -> add(FirErrors.OPT_IN_USAGE) { firDiagnostic ->
OptInUsageImpl( OptInUsageImpl(
firDiagnostic.a, firDiagnostic.a,
@@ -680,6 +680,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = NotAClass::class override val diagnosticClass get() = NotAClass::class
} }
abstract class WrongExtensionFunctionType : KtFirDiagnostic<KtAnnotationEntry>() {
override val diagnosticClass get() = WrongExtensionFunctionType::class
}
abstract class OptInUsage : KtFirDiagnostic<PsiElement>() { abstract class OptInUsage : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = OptInUsage::class override val diagnosticClass get() = OptInUsage::class
abstract val optInMarkerFqName: FqName abstract val optInMarkerFqName: FqName
@@ -816,6 +816,11 @@ internal class NotAClassImpl(
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.NotAClass(), KtAbstractFirDiagnostic<PsiElement> ) : KtFirDiagnostic.NotAClass(), KtAbstractFirDiagnostic<PsiElement>
internal class WrongExtensionFunctionTypeImpl(
override val firDiagnostic: KtPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.WrongExtensionFunctionType(), KtAbstractFirDiagnostic<KtAnnotationEntry>
internal class OptInUsageImpl( internal class OptInUsageImpl(
override val optInMarkerFqName: FqName, override val optInMarkerFqName: FqName,
override val message: String, override val message: String,
@@ -287,6 +287,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val REPEATED_ANNOTATION by error<KtAnnotationEntry>() val REPEATED_ANNOTATION by error<KtAnnotationEntry>()
val REPEATED_ANNOTATION_WARNING by warning<KtAnnotationEntry>() val REPEATED_ANNOTATION_WARNING by warning<KtAnnotationEntry>()
val NOT_A_CLASS by error<PsiElement>() val NOT_A_CLASS by error<PsiElement>()
val WRONG_EXTENSION_FUNCTION_TYPE by error<KtAnnotationEntry>()
} }
val OPT_IN by object : DiagnosticGroup("OptIn") { val OPT_IN by object : DiagnosticGroup("OptIn") {
@@ -253,6 +253,7 @@ object FirErrors {
val REPEATED_ANNOTATION by error0<KtAnnotationEntry>() val REPEATED_ANNOTATION by error0<KtAnnotationEntry>()
val REPEATED_ANNOTATION_WARNING by warning0<KtAnnotationEntry>() val REPEATED_ANNOTATION_WARNING by warning0<KtAnnotationEntry>()
val NOT_A_CLASS by error0<PsiElement>() val NOT_A_CLASS by error0<PsiElement>()
val WRONG_EXTENSION_FUNCTION_TYPE by error0<KtAnnotationEntry>()
// OptIn // OptIn
val OPT_IN_USAGE by warning2<PsiElement, FqName, String>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val OPT_IN_USAGE by warning2<PsiElement, FqName, String>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -12,8 +12,11 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics 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.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.isBuiltinFunctionalType
import org.jetbrains.kotlin.name.StandardClassIds
object FirTypeAnnotationChecker : FirTypeRefChecker() { object FirTypeAnnotationChecker : FirTypeRefChecker() {
override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) { 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)
}
}
} }
} }
} }
@@ -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.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
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_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_GETTER_RETURN_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_INVOCATION_KIND import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_INVOCATION_KIND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.WRONG_LONG_SUFFIX 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" "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(NOT_A_CLASS, "Not a class")
map.put(WRONG_EXTENSION_FUNCTION_TYPE, "ExtensionFunctionType is forbidden on a function type without parameters")
// Exposed visibility group // # // Exposed visibility group // #
map.put( map.put(
@@ -278,6 +278,7 @@ public interface Errors {
DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION_WARNING = DiagnosticFactory0.create(WARNING); DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION_WARNING = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<KtAnnotationEntry> NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<KtAnnotationEntry> NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> WRONG_EXTENSION_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR);
// Annotations // Annotations
@@ -146,6 +146,7 @@ public class DefaultErrorMessages {
MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable"); MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable");
MAP.put(REPEATED_ANNOTATION_WARNING, "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(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_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); 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 package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.isFunctionOrKFunctionTypeWithAnySuspendability
import org.jetbrains.kotlin.config.LanguageFeature.* import org.jetbrains.kotlin.config.LanguageFeature.*
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassDescriptor 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.diagnostics.reportDiagnosticOnce
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass 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.getAnnotationRetention
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotatedWithKotlinRepeatable import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotatedWithKotlinRepeatable
import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil
@@ -163,9 +166,9 @@ class AnnotationChecker(
checkWithoutLanguageFeature: Boolean = false checkWithoutLanguageFeature: Boolean = false
) { ) {
val shouldRunCheck = isSuperType || shouldCheckReferenceItself val shouldRunCheck = isSuperType || shouldCheckReferenceItself
if (shouldRunCheck) {
for (entry in reference.annotationEntries) { for (entry in reference.annotationEntries) {
val descriptor = trace.get(BindingContext.ANNOTATION, entry) val descriptor = trace.get(BindingContext.ANNOTATION, entry)
if (shouldRunCheck) {
if (descriptor is LazyAnnotationDescriptor) { if (descriptor is LazyAnnotationDescriptor) {
/* /*
* There are no users of type annotations until backend, so if there are errors * There are no users of type annotations until backend, so if there are errors
@@ -181,6 +184,12 @@ class AnnotationChecker(
checkAnnotationEntry(entry, actualTargets, trace) 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 val typeArguments = reference.typeElement?.typeArgumentsAsTypes ?: return
for (typeArgument in typeArguments) { 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 // This test checks that annotations on extension function types are preserved. See the corresponding .txt file
@Target(AnnotationTarget.TYPE) @Target(AnnotationTarget.TYPE)
@@ -9,4 +9,12 @@ interface Some {
fun f2(): @ExtensionFunctionType() (String.() -> Int) fun f2(): @ExtensionFunctionType() (String.() -> Int)
fun f3(): @ann String.() -> Int fun f3(): @ann String.() -> Int
fun f4(): @ExtensionFunctionType @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 f2(): kotlin.String.() -> kotlin.Int
public abstract fun f3(): @ann() (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 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 hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
} }
@@ -373,6 +373,9 @@ internal class DescriptorRendererImpl(
append("(") append("(")
if (type.isBuiltinExtensionFunctionalType && type.arguments.size <= 1) {
append("???")
} else {
val parameterTypes = type.getValueParameterTypesFromFunctionType() val parameterTypes = type.getValueParameterTypesFromFunctionType()
for ((index, typeProjection) in parameterTypes.withIndex()) { for ((index, typeProjection) in parameterTypes.withIndex()) {
if (index > 0) append(", ") if (index > 0) append(", ")
@@ -385,6 +388,7 @@ internal class DescriptorRendererImpl(
append(renderTypeProjection(typeProjection)) append(renderTypeProjection(typeProjection))
} }
}
append(") ").append(arrow()).append(" ") append(") ").append(arrow()).append(" ")
renderNormalizedType(type.getReturnTypeFromFunctionType()) renderNormalizedType(type.getReturnTypeFromFunctionType())