From 9ebd665c96e73d4aeb97ffa03775e41fdc6bb97c Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 16 Jul 2021 21:38:08 +0200 Subject: [PATCH] Report error on annotated type inside typeOf on JVM Since it's not feasible to support annotated types in 1.6, we're making this an explicit error in 1.6, so that typeOf can become stable and this feature can be supported in the future without breaking changes to the existing code. Note that extension function types are a special case of annotated types. A separate error is created for them just because the message "annotated types are not supported" would be confusing, since such types don't have explicit annotations in the source code. #KT-29919 --- .../inline/PsiInlineIntrinsicsSupport.kt | 13 ++++- .../codegen/inline/ReifiedTypeInliner.kt | 1 + .../jetbrains/kotlin/codegen/inline/typeOf.kt | 2 + .../diagnostics/DefaultErrorMessagesJvm.java | 2 + .../resolve/jvm/diagnostics/ErrorsJvm.java | 2 + .../jvm/codegen/IrInlineIntrinsicsSupport.kt | 25 ++++++-- .../typeOf/annotatedType.kt | 58 +++++++++++++++++++ .../typeOf/annotatedType.txt | 28 +++++++++ ...gnosticsTestWithJvmIrBackendGenerated.java | 6 ++ 9 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithJvmBackend/typeOf/annotatedType.kt create mode 100644 compiler/testData/diagnostics/testsWithJvmBackend/typeOf/annotatedType.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt index fa4622ebb5a..1cd0dbaab50 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.codegen.inline +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.state.GenerationState @@ -12,12 +13,12 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* -import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND -import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_SUSPEND_TYPE +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.org.objectweb.asm.Type @@ -72,6 +73,14 @@ class PsiInlineIntrinsicsSupport( override fun toKotlinType(type: KotlinType): KotlinType = type + override fun checkAnnotatedType(type: KotlinType) { + if (type.annotations.hasAnnotation(StandardNames.FqNames.extensionFunctionType)) { + state.diagnostics.report(TYPEOF_EXTENSION_FUNCTION_TYPE.on(reportErrorsOn)) + } else if (type.annotations.any { it.fqName != JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION }) { + state.diagnostics.report(TYPEOF_ANNOTATED_TYPE.on(reportErrorsOn)) + } + } + override fun reportSuspendTypeUnsupported() { state.diagnostics.report(TYPEOF_SUSPEND_TYPE.on(reportErrorsOn)) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index 28355d0a903..cfb9be95717 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -75,6 +75,7 @@ class ReifiedTypeInliner( fun toKotlinType(type: KT): KotlinType + fun checkAnnotatedType(type: KT) fun reportSuspendTypeUnsupported() fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt index 47ffb6e100f..d7dfdd6f65a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt @@ -95,6 +95,8 @@ fun TypeSystemCommonBackendContext.generateTypeOf( intrinsicsSupport.reportSuspendTypeUnsupported() } + intrinsicsSupport.checkAnnotatedType(type) + if (intrinsicsSupport.state.stableTypeOf) { if (intrinsicsSupport.isMutableCollectionType(type)) { v.invokestatic(REFLECTION, "mutableCollectionType", Type.getMethodDescriptor(K_TYPE, K_TYPE), false) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java index 2baaa249995..27a526602fc 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java @@ -211,6 +211,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(JVM_INLINE_WITHOUT_VALUE_CLASS, "@JvmInline annotation is only applicable to value classes"); MAP.put(TYPEOF_SUSPEND_TYPE, "Suspend functional types are not supported in typeOf"); + MAP.put(TYPEOF_EXTENSION_FUNCTION_TYPE, "Extension function types are not supported in typeOf"); + MAP.put(TYPEOF_ANNOTATED_TYPE, "Annotated types are not supported in typeOf"); MAP.put(TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND, "Non-reified type parameters with recursive bounds are not supported yet: {0}", STRING); } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java index 981d7fb996e..438b580aa2d 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java @@ -178,6 +178,8 @@ public interface ErrorsJvm { DiagnosticFactory0 JVM_INLINE_WITHOUT_VALUE_CLASS = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 TYPEOF_SUSPEND_TYPE = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 TYPEOF_EXTENSION_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 TYPEOF_ANNOTATED_TYPE = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND = DiagnosticFactory1.create(ERROR); @SuppressWarnings("UnusedDeclaration") diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt index d6b106d13ee..2b0ea5060c4 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt @@ -7,8 +7,10 @@ package org.jetbrains.kotlin.backend.jvm.codegen import org.jetbrains.kotlin.backend.common.ir.allParametersCount import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmSymbols import org.jetbrains.kotlin.backend.jvm.intrinsics.SignatureString import org.jetbrains.kotlin.backend.jvm.lower.FunctionReferenceLowering +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner @@ -19,13 +21,11 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classOrNull -import org.jetbrains.kotlin.ir.util.defaultType -import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable -import org.jetbrains.kotlin.ir.util.render +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* -import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND -import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_SUSPEND_TYPE +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.org.objectweb.asm.Type @@ -114,6 +114,21 @@ class IrInlineIntrinsicsSupport( override fun toKotlinType(type: IrType): KotlinType = type.toIrBasedKotlinType() + override fun checkAnnotatedType(type: IrType) { + if (type.hasAnnotation(StandardNames.FqNames.extensionFunctionType)) { + context.psiErrorBuilder.at(reportErrorsOn, containingFile).report(TYPEOF_EXTENSION_FUNCTION_TYPE) + } else if (type.annotations.any { !it.symbol.owner.constructedClass.isSpecialAnnotation() }) { + context.psiErrorBuilder.at(reportErrorsOn, containingFile).report(TYPEOF_ANNOTATED_TYPE) + } + } + + // TODO: consider inventing a safer way to do this + private fun IrClass.isSpecialAnnotation(): Boolean = + hasEqualFqName(JvmAnnotationNames.ENHANCED_NULLABILITY_ANNOTATION) || + hasEqualFqName(JvmSymbols.FLEXIBLE_NULLABILITY_ANNOTATION_FQ_NAME) || + hasEqualFqName(JvmSymbols.FLEXIBLE_MUTABILITY_ANNOTATION_FQ_NAME) || + hasEqualFqName(JvmSymbols.RAW_TYPE_ANNOTATION_FQ_NAME) + override fun reportSuspendTypeUnsupported() { context.psiErrorBuilder.at(reportErrorsOn, containingFile).report(TYPEOF_SUSPEND_TYPE) } diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/annotatedType.kt b/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/annotatedType.kt new file mode 100644 index 00000000000..94b1ad8d792 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/annotatedType.kt @@ -0,0 +1,58 @@ +// WITH_RUNTIME +// USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi +// TARGET_BACKEND: JVM_IR + +import kotlin.reflect.* + +inline fun f() = g>() +inline fun g() = typeOf() + +inline fun a() = typeOf<@Runtime Z>() + +@Target(AnnotationTarget.TYPE) +@Retention(AnnotationRetention.RUNTIME) +annotation class Runtime + +@Target(AnnotationTarget.TYPE) +@Retention(AnnotationRetention.BINARY) +annotation class Binary + +@Target(AnnotationTarget.TYPE) +@Retention(AnnotationRetention.SOURCE) +annotation class Source + +fun test() { + typeOf Int>() + f Unit>() + + typeOf List>() + f Array<*>>() + + typeOf<@Runtime Int.() -> List>() + f<@Runtime Unit.() -> Array<*>>() + + typeOf<@Runtime String>() + f<@Runtime String>() + typeOf<@Binary String>() + f<@Binary String>() + typeOf<@Source String>() + f<@Source String>() + + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + typeOf<@kotlin.internal.Exact String>() + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + f<@kotlin.internal.Exact String>() + + typeOf>>() + f>>() + + // TODO: https://youtrack.jetbrains.com/issue/KT-29919#focus=Comments-27-5065356.0-0 + a() + + test2() +} + +inline fun test2() { + typeOf<@Runtime R.()->Unit>() + typeOfUnit>() +} diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/annotatedType.txt b/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/annotatedType.txt new file mode 100644 index 00000000000..5cfd39ae8df --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/annotatedType.txt @@ -0,0 +1,28 @@ +package + +public inline fun a(): kotlin.reflect.KType +public inline fun f(): kotlin.reflect.KType +public inline fun g(): kotlin.reflect.KType +public fun test(): kotlin.Unit +public inline fun test2(): kotlin.Unit + +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) public final annotation class Binary : kotlin.Annotation { + public constructor Binary() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.Retention(value = AnnotationRetention.RUNTIME) public final annotation class Runtime : kotlin.Annotation { + public constructor Runtime() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPE}) @kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) public final annotation class Source : kotlin.Annotation { + public constructor Source() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java index 77f23fc3e38..6112b33c7f1 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithJvmIrBackendGenerated.java @@ -672,6 +672,12 @@ public class DiagnosticsTestWithJvmIrBackendGenerated extends AbstractDiagnostic KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend/typeOf"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @Test + @TestMetadata("annotatedType.kt") + public void testAnnotatedType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithJvmBackend/typeOf/annotatedType.kt"); + } + @Test @TestMetadata("nonReifiedTypeParameterWithRecursiveBound.kt") public void testNonReifiedTypeParameterWithRecursiveBound() throws Exception {