[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:
+2
-1
@@ -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)
|
||||
|
||||
|
||||
compiler/testData/codegen/box/reflection/typeOf/nonReifiedTypeParameters/recursiveBoundWithInline.kt
Vendored
+25
@@ -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"
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
An operation is not implemented: Non-reified type parameters with recursive bounds are not supported yet
|
||||
+16
@@ -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"
|
||||
}
|
||||
+1
@@ -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")
|
||||
}
|
||||
|
||||
Generated
+10
@@ -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");
|
||||
|
||||
Generated
+10
@@ -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");
|
||||
|
||||
+10
@@ -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");
|
||||
|
||||
+6
-1
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user