From 340512e27ae06b7331c970d3d9f64c8ebe84402a Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Fri, 10 Jul 2020 02:45:30 +0300 Subject: [PATCH] [KJS] Throw exception on recursive types provided to typeOf and provide proper support later within KT-40173 #KT-38140 fixed --- .../js/lower/ClassReferenceLowering.kt | 3 +- .../recursiveBoundWithInline.kt | 25 ++++++++++++++++ .../recursiveBoundWithInline.kt.fail | 1 + .../recursiveBoundWithoutInline.kt | 16 ++++++++++ .../recursiveBoundWithoutInline.kt.fail | 1 + .../ast/metadata/metadataProperties.kt | 17 +++-------- .../js/inline/clean/substituteKTypes.kt | 29 +++++++++++++++---- .../IrJsCodegenBoxES6TestGenerated.java | 10 +++++++ .../IrJsCodegenBoxTestGenerated.java | 10 +++++++ .../semantics/JsCodegenBoxTestGenerated.java | 10 +++++++ .../functions/factories/TypeOfFIF.kt | 7 ++++- 11 files changed, 108 insertions(+), 21 deletions(-) create mode 100644 compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt.fail create mode 100644 compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt.fail diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt index 8385567a2e5..2500c038043 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/ClassReferenceLowering.kt @@ -196,7 +196,8 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass } private fun createKTypeParameter(typeParameter: IrTypeParameter, visitedTypeParams: MutableSet): IrExpression { - if (typeParameter in visitedTypeParams) return buildCall(context.intrinsics.getStarKTypeProjection!!) + // See KT-40173 + if (typeParameter in visitedTypeParams) TODO("Non-reified type parameters with recursive bounds are not supported yet") visitedTypeParams.add(typeParameter) diff --git a/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt b/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt new file mode 100644 index 00000000000..05dc2a70845 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt @@ -0,0 +1,25 @@ +// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi +// TODO: it should target all backends, but now it's possible to have only one .fial file per test file, +// so we can't define different messages for different test suites/runners. +// TARGET_BACKEND: JS +// KJS_WITH_FULL_RUNTIME + +import kotlin.reflect.typeOf + +fun > foo() { + bar>() + baz>() +} + +inline fun bar() { + baz() +} + +inline fun baz() { + typeOf>() +} + +fun box(): String { + foo() + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt.fail b/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt.fail new file mode 100644 index 00000000000..9803cffba2d --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt.fail @@ -0,0 +1 @@ +An operation is not implemented: Non-reified type parameters with recursive bounds are not supported yet \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt b/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt new file mode 100644 index 00000000000..ea49c1e1127 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt @@ -0,0 +1,16 @@ +// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi +// TODO: it should target all backends, but now it's possible to have only one .fial file per test file, +// so we can't define different messages for different test suites/runners. +// TARGET_BACKEND: JS +// KJS_WITH_FULL_RUNTIME + +import kotlin.reflect.typeOf + +fun > foo() { + typeOf>() +} + +fun box(): String { + foo() + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt.fail b/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt.fail new file mode 100644 index 00000000000..9803cffba2d --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt.fail @@ -0,0 +1 @@ +An operation is not implemented: Non-reified type parameters with recursive bounds are not supported yet \ No newline at end of file diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt index b1be72cb9d3..0aec0c1693c 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @file:JvmName("MetadataProperties") @@ -129,6 +118,8 @@ var JsExpression.primitiveKClass: JsExpression? by MetadataProperty(default = nu var JsExpression.kType: JsExpression? by MetadataProperty(default = null) +var JsExpression.kTypeWithRecursion: Boolean by MetadataProperty(default = false) + data class CoroutineMetadata( val doResumeName: JsName, val stateName: JsName, diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/substituteKTypes.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/substituteKTypes.kt index f8a28b05362..d7dfc75ae3d 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/substituteKTypes.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/substituteKTypes.kt @@ -1,24 +1,27 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.js.inline.clean import org.jetbrains.kotlin.js.backend.ast.* -import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction -import org.jetbrains.kotlin.js.backend.ast.metadata.kType -import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction -import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef +import org.jetbrains.kotlin.js.backend.ast.metadata.* // Replaces getReifiedTypeParameterKType() with its KType fun substituteKTypes(root: JsNode) { val visitor = object : JsVisitorWithContextImpl() { override fun endVisit(invocation: JsInvocation, ctx: JsContext) { + // for invocations from non-inline contexts + invocation.checkDoesNotCreateRecursiveKType() + val qualifier = invocation.qualifier as? JsNameRef ?: return if (qualifier.name?.specialFunction != SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE) return + val firstArg = invocation.arguments.first() getTransitiveKType(firstArg)?.let { + // for invocations from inline contexts + it.checkNoInvocationsWithRecursiveKType() ctx.replaceMe(it) } } @@ -30,7 +33,7 @@ fun substituteKTypes(root: JsNode) { // kType metadata is set on jsClass expressions. // There can be a chain of local variables from jsClass to its usage. // This methods uses staticRef to find the original expression with kType metadata. -fun getTransitiveKType(e: JsExpression): JsExpression? { +private fun getTransitiveKType(e: JsExpression): JsExpression? { return when { e.kType != null -> e.kType @@ -43,3 +46,17 @@ fun getTransitiveKType(e: JsExpression): JsExpression? { else -> null } } + +private fun JsExpression.checkNoInvocationsWithRecursiveKType() { + val visitor = object : JsVisitorWithContextImpl() { + override fun endVisit(invocation: JsInvocation, ctx: JsContext) { + invocation.checkDoesNotCreateRecursiveKType() + } + } + visitor.accept(this) +} + +private fun JsInvocation.checkDoesNotCreateRecursiveKType() { + // See KT-40173 + if (kTypeWithRecursion) TODO("Non-reified type parameters with recursive bounds are not supported yet") +} diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 95b002e70fc..e0ac69e837d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -22412,6 +22412,16 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/innerGeneric.kt"); } + @TestMetadata("recursiveBoundWithInline.kt") + public void testRecursiveBoundWithInline() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt"); + } + + @TestMetadata("recursiveBoundWithoutInline.kt") + public void testRecursiveBoundWithoutInline() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt"); + } + @TestMetadata("simpleClassParameter.kt") public void testSimpleClassParameter() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/simpleClassParameter.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 61f8cf6ab45..1e452436e78 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -22412,6 +22412,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/innerGeneric.kt"); } + @TestMetadata("recursiveBoundWithInline.kt") + public void testRecursiveBoundWithInline() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt"); + } + + @TestMetadata("recursiveBoundWithoutInline.kt") + public void testRecursiveBoundWithoutInline() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt"); + } + @TestMetadata("simpleClassParameter.kt") public void testSimpleClassParameter() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/simpleClassParameter.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 27e14b4b9b9..1341e95d46c 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -22427,6 +22427,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/innerGeneric.kt"); } + @TestMetadata("recursiveBoundWithInline.kt") + public void testRecursiveBoundWithInline() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt"); + } + + @TestMetadata("recursiveBoundWithoutInline.kt") + public void testRecursiveBoundWithoutInline() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithoutInline.kt"); + } + @TestMetadata("simpleClassParameter.kt") public void testSimpleClassParameter() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/simpleClassParameter.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TypeOfFIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TypeOfFIF.kt index 578ab341033..803a5597fd2 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TypeOfFIF.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TypeOfFIF.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction +import org.jetbrains.kotlin.js.backend.ast.metadata.kTypeWithRecursion import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo import org.jetbrains.kotlin.js.translate.context.Namer @@ -146,7 +147,11 @@ private class KTypeConstructor(private val context: TranslationContext) { ) } - if (typeParameter in visitedTypeParams) return callHelperFunction(Namer.GET_START_KTYPE_PROJECTION) + if (typeParameter in visitedTypeParams) { + return callHelperFunction(Namer.GET_START_KTYPE_PROJECTION).also { + it.kTypeWithRecursion = true + } + } visitedTypeParams.add(typeParameter)