From 438ce571837e9e83f872bbb55e56c6314b857c60 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 6 Jul 2021 16:10:01 +0200 Subject: [PATCH] Report error on `typeOf()` Otherwise an invalid type is constructed which causes kotlin-reflect to crash, and stdlib implementation to render the type incorrectly. The reason is that suspend functional types are not properly supported in reflection. Once they are supported, this error can be removed. #KT-47562 --- .../kotlin/codegen/ExpressionCodegen.java | 6 ++++-- .../kotlin/codegen/inline/PsiInlineCodegen.kt | 5 +++-- .../codegen/inline/PsiInlineIntrinsicsSupport.kt | 11 ++++++++++- .../kotlin/codegen/inline/ReifiedTypeInliner.kt | 2 ++ .../jetbrains/kotlin/codegen/inline/typeOf.kt | 5 +++++ .../jvm/diagnostics/DefaultErrorMessagesJvm.java | 2 ++ .../resolve/jvm/diagnostics/ErrorsJvm.java | 2 ++ .../backend/jvm/codegen/ExpressionCodegen.kt | 2 +- .../jvm/codegen/IrInlineIntrinsicsSupport.kt | 10 +++++++++- .../kotlin/backend/jvm/intrinsics/TypeOf.kt | 4 +++- .../testsWithJvmBackend/typeOf/suspendType.kt | 12 ++++++++++++ .../testsWithJvmBackend/typeOf/suspendType.txt | 5 +++++ ...DiagnosticsTestWithJvmIrBackendGenerated.java | 16 ++++++++++++++++ ...iagnosticsTestWithOldJvmBackendGenerated.java | 16 ++++++++++++++++ 14 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.kt create mode 100644 compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 47fface0da8..e7fcfb1368d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2971,8 +2971,10 @@ public class ExpressionCodegen extends KtVisitor impleme if (isDefaultCompilation) { return new InlineCodegenForDefaultBody(functionDescriptor, this, state, signature, sourceCompiler); } else { - return new PsiInlineCodegen(this, state, functionDescriptor, signature, typeParameterMappings, sourceCompiler, - typeMapper.mapImplementationOwner(functionDescriptor), typeMapper.mapOwner(descriptor)); + return new PsiInlineCodegen( + this, state, functionDescriptor, signature, typeParameterMappings, sourceCompiler, + typeMapper.mapImplementationOwner(functionDescriptor), typeMapper.mapOwner(descriptor), callElement + ); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt index 13882029da0..896bd08873f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt @@ -43,11 +43,12 @@ class PsiInlineCodegen( typeParameterMappings: TypeParameterMappings, sourceCompiler: SourceCompilerForInline, private val methodOwner: Type, - private val actualDispatchReceiver: Type + private val actualDispatchReceiver: Type, + reportErrorsOn: KtElement, ) : InlineCodegen( codegen, state, signature, typeParameterMappings, sourceCompiler, ReifiedTypeInliner( - typeParameterMappings, PsiInlineIntrinsicsSupport(state), codegen.typeSystem, + typeParameterMappings, PsiInlineIntrinsicsSupport(state, reportErrorsOn), codegen.typeSystem, state.languageVersionSettings, state.unifiedNullChecks ), ), CallGenerator { 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 4e84806533f..cce2c4699e7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineIntrinsicsSupport.kt @@ -12,8 +12,10 @@ 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.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_SUSPEND_TYPE import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.org.objectweb.asm.Type @@ -21,7 +23,10 @@ import org.jetbrains.org.objectweb.asm.Type.INT_TYPE import org.jetbrains.org.objectweb.asm.Type.VOID_TYPE import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter -class PsiInlineIntrinsicsSupport(override val state: GenerationState) : ReifiedTypeInliner.IntrinsicsSupport { +class PsiInlineIntrinsicsSupport( + override val state: GenerationState, + private val reportErrorsOn: KtElement, +) : ReifiedTypeInliner.IntrinsicsSupport { override fun putClassInstance(v: InstructionAdapter, type: KotlinType) { DescriptorAsmUtil.putJavaLangClassInstance(v, state.typeMapper.mapType(type), type, state.typeMapper) } @@ -64,4 +69,8 @@ class PsiInlineIntrinsicsSupport(override val state: GenerationState) : ReifiedT } override fun toKotlinType(type: KotlinType): KotlinType = type + + 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 d6332baf934..56ac7c8c1b0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -73,6 +73,8 @@ class ReifiedTypeInliner( fun isMutableCollectionType(type: KT): Boolean fun toKotlinType(type: KT): KotlinType + + fun reportSuspendTypeUnsupported() } companion object { 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 9931d3cc511..949db478f7f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.codegen.inline +import org.jetbrains.kotlin.builtins.isSuspendFunctionType import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext @@ -90,6 +91,10 @@ fun TypeSystemCommonBackendContext.generateTypeOf( v.invokestatic(REFLECTION, methodName, signature, false) + if (intrinsicsSupport.toKotlinType(type).isSuspendFunctionType) { + intrinsicsSupport.reportSuspendTypeUnsupported() + } + 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 72d843f146f..83b9d43b05c 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 @@ -208,6 +208,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION, "Value classes without @JvmInline annotation are not supported yet"); 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"); } @NotNull 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 35b0c2e38e9..946feaeecb0 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 @@ -175,6 +175,8 @@ public interface ErrorsJvm { DiagnosticFactory0 VALUE_CLASS_WITHOUT_JVM_INLINE_ANNOTATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 JVM_INLINE_WITHOUT_VALUE_CLASS = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 TYPEOF_SUSPEND_TYPE = DiagnosticFactory0.create(ERROR); + @SuppressWarnings("UnusedDeclaration") Object _initializer = new Object() { { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index e89d3a443a4..ee3af74557d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -1448,7 +1448,7 @@ class ExpressionCodegen( val reifiedTypeInliner = ReifiedTypeInliner( mappings, - IrInlineIntrinsicsSupport(context, typeMapper), + IrInlineIntrinsicsSupport(context, typeMapper, element, irFunction.fileParent), context.typeSystem, state.languageVersionSettings, state.unifiedNullChecks, 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 2c44bb383f3..4f9dbdead58 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 @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType +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 @@ -22,6 +23,7 @@ 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.resolve.jvm.AsmTypes.* +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.TYPEOF_SUSPEND_TYPE import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.org.objectweb.asm.Type @@ -31,7 +33,9 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter class IrInlineIntrinsicsSupport( private val context: JvmBackendContext, - private val typeMapper: IrTypeMapper + private val typeMapper: IrTypeMapper, + private val reportErrorsOn: IrExpression, + private val containingFile: IrFile, ) : ReifiedTypeInliner.IntrinsicsSupport { override val state: GenerationState get() = context.state @@ -107,4 +111,8 @@ class IrInlineIntrinsicsSupport( } override fun toKotlinType(type: IrType): KotlinType = type.toIrBasedKotlinType() + + override fun reportSuspendTypeUnsupported() { + context.psiErrorBuilder.at(reportErrorsOn, containingFile).report(TYPEOF_SUSPEND_TYPE) + } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt index 9615ed38b67..2aad0a23d30 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.backend.jvm.codegen.IrInlineIntrinsicsSupport +import org.jetbrains.kotlin.backend.jvm.codegen.fileParent import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner import org.jetbrains.kotlin.codegen.inline.generateTypeOf import org.jetbrains.kotlin.codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter @@ -19,7 +20,8 @@ object TypeOf : IntrinsicMethod() { if (putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.TYPE_OF)) { mv.aconst(null) // see ReifiedTypeInliner.processTypeOf } else { - typeMapper.typeSystem.generateTypeOf(mv, type, IrInlineIntrinsicsSupport(context, typeMapper)) + val support = IrInlineIntrinsicsSupport(context, typeMapper, expression, codegen.irFunction.fileParent) + typeMapper.typeSystem.generateTypeOf(mv, type, support) } expression.onStack } diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.kt b/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.kt new file mode 100644 index 00000000000..234443f86fc --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.kt @@ -0,0 +1,12 @@ +// WITH_RUNTIME +// USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi + +import kotlin.reflect.* + +inline fun f() = g>() +inline fun g() = typeOf() + +fun test() { + typeOf Int>() + f Unit>() +} diff --git a/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.txt b/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.txt new file mode 100644 index 00000000000..8e396ee5feb --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.txt @@ -0,0 +1,5 @@ +package + +public inline fun f(): kotlin.reflect.KType +public inline fun g(): kotlin.reflect.KType +public fun test(): kotlin.Unit 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 5df794c0fb2..986c3e97aa8 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 @@ -663,6 +663,22 @@ public class DiagnosticsTestWithJvmIrBackendGenerated extends AbstractDiagnostic } } + @Nested + @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/typeOf") + @TestDataPath("$PROJECT_ROOT") + public class TypeOf { + @Test + public void testAllFilesPresentInTypeOf() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend/typeOf"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("suspendType.kt") + public void testSuspendType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/valueClasses") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java index cb5f874a886..853c5e62955 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsTestWithOldJvmBackendGenerated.java @@ -651,6 +651,22 @@ public class DiagnosticsTestWithOldJvmBackendGenerated extends AbstractDiagnosti } } + @Nested + @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/typeOf") + @TestDataPath("$PROJECT_ROOT") + public class TypeOf { + @Test + public void testAllFilesPresentInTypeOf() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJvmBackend/typeOf"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_OLD, true); + } + + @Test + @TestMetadata("suspendType.kt") + public void testSuspendType() throws Exception { + runTest("compiler/testData/diagnostics/testsWithJvmBackend/typeOf/suspendType.kt"); + } + } + @Nested @TestMetadata("compiler/testData/diagnostics/testsWithJvmBackend/valueClasses") @TestDataPath("$PROJECT_ROOT")