diff options
author | Zalim Bashorov <zalim.bashorov@jetbrains.com> | 2020-07-10 02:45:30 +0300 |
---|---|---|
committer | Zalim Bashorov <zalim.bashorov@jetbrains.com> | 2020-07-14 18:49:34 +0300 |
commit | c6749451c2359d7415aa0783f895bedb18ed2409 (patch) | |
tree | 1e055693128780c200648a44142bc77a6ab29954 | |
parent | af80a0a8cdbef1e7566c9335a8a73e65ad1e650c (diff) | |
download | kotlin-c6749451c2359d7415aa0783f895bedb18ed2409.tar.gz |
[KJS] Throw exception on recursive types provided to typeOf and provide proper support later within KT-40173
#KT-38140 fixed
(cherry picked from commit 340512e27ae06b7331c970d3d9f64c8ebe84402a)
11 files changed, 108 insertions, 21 deletions
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<IrTypeParameter>): 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 <T : Comparable<T>> foo() { + bar<List<T>>() + baz<List<T>>() +} + +inline fun <reified T> bar() { + baz<T>() +} + +inline fun <reified T> baz() { + typeOf<Set<T>>() +} + +fun box(): String { + foo<Int>() + 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 <T : Comparable<T>> foo() { + typeOf<List<T>>() +} + +fun box(): String { + foo<Int>() + 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(<Class Constructor>) with its KType fun substituteKTypes(root: JsNode) { val visitor = object : JsVisitorWithContextImpl() { override fun endVisit(invocation: JsInvocation, ctx: JsContext<in JsNode>) { + // 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<in JsNode>) { + 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 711a144ef9d..5dc406443fc 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 @@ -22368,6 +22368,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 cea4a3dc20b..1076cde05ce 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 @@ -22368,6 +22368,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 3b769e9b9bc..5c95e5b4649 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 @@ -22383,6 +22383,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) |