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
This commit is contained in:
Alexander Udalov
2021-07-16 21:38:08 +02:00
parent a383d45534
commit 9ebd665c96
9 changed files with 130 additions and 7 deletions

View File

@@ -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))
}

View File

@@ -75,6 +75,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
fun toKotlinType(type: KT): KotlinType
fun checkAnnotatedType(type: KT)
fun reportSuspendTypeUnsupported()
fun reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameterName: Name)
}

View File

@@ -95,6 +95,8 @@ fun <KT : KotlinTypeMarker> 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)

View File

@@ -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);
}

View File

@@ -178,6 +178,8 @@ public interface ErrorsJvm {
DiagnosticFactory0<PsiElement> JVM_INLINE_WITHOUT_VALUE_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> TYPEOF_SUSPEND_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> TYPEOF_EXTENSION_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> TYPEOF_ANNOTATED_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> TYPEOF_NON_REIFIED_TYPE_PARAMETER_WITH_RECURSIVE_BOUND = DiagnosticFactory1.create(ERROR);
@SuppressWarnings("UnusedDeclaration")

View File

@@ -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)
}

View File

@@ -0,0 +1,58 @@
// WITH_RUNTIME
// USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM_IR
import kotlin.reflect.*
inline fun <reified X> f() = g<List<X>>()
inline fun <reified Y> g() = typeOf<Y>()
inline fun <reified Z> 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_EXTENSION_FUNCTION_TYPE!>typeOf<String.() -> Int>()<!>
<!TYPEOF_EXTENSION_FUNCTION_TYPE!>f<Int.(Int) -> Unit>()<!>
<!TYPEOF_EXTENSION_FUNCTION_TYPE, TYPEOF_SUSPEND_TYPE!>typeOf<suspend Int.() -> List<String>>()<!>
<!TYPEOF_EXTENSION_FUNCTION_TYPE, TYPEOF_SUSPEND_TYPE!>f<suspend Unit.() -> Array<*>>()<!>
<!TYPEOF_EXTENSION_FUNCTION_TYPE!>typeOf<@Runtime Int.() -> List<String>>()<!>
<!TYPEOF_EXTENSION_FUNCTION_TYPE!>f<@Runtime Unit.() -> Array<*>>()<!>
<!TYPEOF_ANNOTATED_TYPE!>typeOf<@Runtime String>()<!>
<!TYPEOF_ANNOTATED_TYPE!>f<@Runtime String>()<!>
<!TYPEOF_ANNOTATED_TYPE!>typeOf<@Binary String>()<!>
<!TYPEOF_ANNOTATED_TYPE!>f<@Binary String>()<!>
<!TYPEOF_ANNOTATED_TYPE!>typeOf<@Source String>()<!>
<!TYPEOF_ANNOTATED_TYPE!>f<@Source String>()<!>
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
<!TYPEOF_ANNOTATED_TYPE!>typeOf<@kotlin.internal.Exact String>()<!>
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
<!TYPEOF_ANNOTATED_TYPE!>f<@kotlin.internal.Exact String>()<!>
<!TYPEOF_ANNOTATED_TYPE!>typeOf<Map<String, List<@Runtime Int>>>()<!>
<!TYPEOF_ANNOTATED_TYPE!>f<Map<String, List<@Runtime Int>>>()<!>
// TODO: https://youtrack.jetbrains.com/issue/KT-29919#focus=Comments-27-5065356.0-0
a<String>()
test2<String>()
}
inline fun <reified R> test2() {
<!TYPEOF_EXTENSION_FUNCTION_TYPE!>typeOf<@Runtime R.()->Unit>()<!>
<!TYPEOF_EXTENSION_FUNCTION_TYPE!>typeOf<R.()->Unit>()<!>
}

View File

@@ -0,0 +1,28 @@
package
public inline fun </*0*/ reified Z> a(): kotlin.reflect.KType
public inline fun </*0*/ reified X> f(): kotlin.reflect.KType
public inline fun </*0*/ reified Y> g(): kotlin.reflect.KType
public fun test(): kotlin.Unit
public inline fun </*0*/ reified R> 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
}

View File

@@ -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 {