[KJS] Throw exception on recursive types provided to typeOf and provide proper support later within KT-40173

#KT-38140 fixed
This commit is contained in:
Zalim Bashorov
2020-07-10 02:45:30 +03:00
parent c552933459
commit 340512e27a
11 changed files with 108 additions and 21 deletions
@@ -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)
@@ -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"
}
@@ -0,0 +1 @@
An operation is not implemented: Non-reified type parameters with recursive bounds are not supported yet
@@ -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"
}
@@ -0,0 +1 @@
An operation is not implemented: Non-reified type parameters with recursive bounds are not supported yet
@@ -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,
@@ -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")
}
@@ -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");
@@ -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");
@@ -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");
@@ -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)