[JS BEs] use star projection when type parameter used recursively
#KT-37128 Fixed
This commit is contained in:
Generated
+5
@@ -25201,6 +25201,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedTypeArgumentWithRecursion.kt")
|
||||||
|
public void testReifiedTypeArgumentWithRecursion() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithRecursion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("safecast.kt")
|
@TestMetadata("safecast.kt")
|
||||||
public void testSafecast() throws Exception {
|
public void testSafecast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
||||||
|
|||||||
+21
-14
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -136,9 +136,10 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createKType(type: IrType): IrExpression {
|
private fun createKType(type: IrType, visitedTypeParams: MutableSet<IrTypeParameter>): IrExpression {
|
||||||
|
|
||||||
if (type is IrSimpleType)
|
if (type is IrSimpleType)
|
||||||
return createSimpleKType(type)
|
return createSimpleKType(type, visitedTypeParams)
|
||||||
if (type is IrDynamicType)
|
if (type is IrDynamicType)
|
||||||
return createDynamicType()
|
return createDynamicType()
|
||||||
error("Unexpected type $type")
|
error("Unexpected type $type")
|
||||||
@@ -148,7 +149,7 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass
|
|||||||
return buildCall(context.intrinsics.createDynamicKType!!)
|
return buildCall(context.intrinsics.createDynamicKType!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createSimpleKType(type: IrSimpleType): IrExpression {
|
private fun createSimpleKType(type: IrSimpleType, visitedTypeParams: MutableSet<IrTypeParameter>): IrExpression {
|
||||||
val classifier: IrClassifierSymbol = type.classifier
|
val classifier: IrClassifierSymbol = type.classifier
|
||||||
|
|
||||||
// TODO: Check why do we have un-substituted reified parameters
|
// TODO: Check why do we have un-substituted reified parameters
|
||||||
@@ -156,9 +157,9 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass
|
|||||||
// error("Fail")
|
// error("Fail")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
val kClassifier = createKClassifier(classifier)
|
val kClassifier = createKClassifier(classifier, visitedTypeParams)
|
||||||
// TODO: Use static array types
|
// TODO: Use static array types
|
||||||
val arguments = type.arguments.map { createKTypeProjection(it) }.toJsArrayLiteral(
|
val arguments = type.arguments.map { createKTypeProjection(it, visitedTypeParams) }.toJsArrayLiteral(
|
||||||
context,
|
context,
|
||||||
context.dynamicType,
|
context.dynamicType,
|
||||||
context.dynamicType
|
context.dynamicType
|
||||||
@@ -172,7 +173,7 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createKTypeProjection(tp: IrTypeArgument): IrExpression {
|
private fun createKTypeProjection(tp: IrTypeArgument, visitedTypeParams: MutableSet<IrTypeParameter>): IrExpression {
|
||||||
if (tp !is IrTypeProjection) {
|
if (tp !is IrTypeProjection) {
|
||||||
return buildCall(context.intrinsics.getStarKTypeProjection!!)
|
return buildCall(context.intrinsics.getStarKTypeProjection!!)
|
||||||
}
|
}
|
||||||
@@ -183,20 +184,24 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass
|
|||||||
Variance.OUT_VARIANCE -> context.intrinsics.createCovariantKTypeProjection!!
|
Variance.OUT_VARIANCE -> context.intrinsics.createCovariantKTypeProjection!!
|
||||||
}
|
}
|
||||||
|
|
||||||
val kType = createKType(tp.type)
|
val kType = createKType(tp.type, visitedTypeParams)
|
||||||
return buildCall(factoryName, kType)
|
return buildCall(factoryName, kType)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createKClassifier(classifier: IrClassifierSymbol): IrExpression =
|
private fun createKClassifier(classifier: IrClassifierSymbol, visitedTypeParams: MutableSet<IrTypeParameter>): IrExpression =
|
||||||
when (classifier) {
|
when (classifier) {
|
||||||
is IrTypeParameterSymbol -> createKTypeParameter(classifier.owner)
|
is IrTypeParameterSymbol -> createKTypeParameter(classifier.owner, visitedTypeParams)
|
||||||
else -> callGetKClass(typeArgument = classifier.defaultType)
|
else -> callGetKClass(typeArgument = classifier.defaultType)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createKTypeParameter(typeParameter: IrTypeParameter): IrExpression {
|
private fun createKTypeParameter(typeParameter: IrTypeParameter, visitedTypeParams: MutableSet<IrTypeParameter>): IrExpression {
|
||||||
|
if (typeParameter in visitedTypeParams) return buildCall(context.intrinsics.getStarKTypeProjection!!)
|
||||||
|
|
||||||
|
visitedTypeParams.add(typeParameter)
|
||||||
|
|
||||||
val name = JsIrBuilder.buildString(context.irBuiltIns.stringType, typeParameter.name.asString())
|
val name = JsIrBuilder.buildString(context.irBuiltIns.stringType, typeParameter.name.asString())
|
||||||
val upperBounds = typeParameter.superTypes.map { createKType(it) }.toJsArrayLiteral(
|
val upperBounds = typeParameter.superTypes.map { createKType(it, visitedTypeParams) }.toJsArrayLiteral(
|
||||||
context,
|
context,
|
||||||
context.dynamicType,
|
context.dynamicType,
|
||||||
context.dynamicType
|
context.dynamicType
|
||||||
@@ -218,7 +223,9 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass
|
|||||||
name,
|
name,
|
||||||
upperBounds,
|
upperBounds,
|
||||||
variance
|
variance
|
||||||
)
|
).also {
|
||||||
|
visitedTypeParams.remove(typeParameter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||||
@@ -238,7 +245,7 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass
|
|||||||
|
|
||||||
override fun visitCall(expression: IrCall): IrExpression =
|
override fun visitCall(expression: IrCall): IrExpression =
|
||||||
if (Symbols.isTypeOfIntrinsic(expression.symbol)) {
|
if (Symbols.isTypeOfIntrinsic(expression.symbol)) {
|
||||||
createKType(expression.getTypeArgument(0)!!)
|
createKType(expression.getTypeArgument(0)!!, hashSetOf())
|
||||||
} else {
|
} else {
|
||||||
super.visitCall(expression)
|
super.visitCall(expression)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// IGNORE_BACKEND_FIR: JVM_IR
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// KJS_WITH_FULL_RUNTIME
|
||||||
|
|
||||||
|
// See KT-37128
|
||||||
|
|
||||||
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
|
// TODO check real effects to fix the behavior when we reach consensus
|
||||||
|
// and to be sure that something is not dropped by optimizations.
|
||||||
|
|
||||||
|
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||||
|
inline fun <reified T> T.causeBug() {
|
||||||
|
val x = this
|
||||||
|
x is T
|
||||||
|
x as T
|
||||||
|
T::class
|
||||||
|
typeOf<T>()
|
||||||
|
Array<T>(1) { x }
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SomeToImplement<SELF_TVAR>
|
||||||
|
|
||||||
|
class Y : SomeToImplement<Y>
|
||||||
|
|
||||||
|
class Something<T> where T: SomeToImplement<T> {
|
||||||
|
fun op() = causeBug()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
Something<Y>().op()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+5
@@ -26717,6 +26717,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedTypeArgumentWithRecursion.kt")
|
||||||
|
public void testReifiedTypeArgumentWithRecursion() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithRecursion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("safecast.kt")
|
@TestMetadata("safecast.kt")
|
||||||
public void testSafecast() throws Exception {
|
public void testSafecast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
||||||
|
|||||||
+5
@@ -25534,6 +25534,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedTypeArgumentWithRecursion.kt")
|
||||||
|
public void testReifiedTypeArgumentWithRecursion() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithRecursion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("safecast.kt")
|
@TestMetadata("safecast.kt")
|
||||||
public void testSafecast() throws Exception {
|
public void testSafecast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
||||||
|
|||||||
+5
@@ -25201,6 +25201,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedTypeArgumentWithRecursion.kt")
|
||||||
|
public void testReifiedTypeArgumentWithRecursion() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithRecursion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("safecast.kt")
|
@TestMetadata("safecast.kt")
|
||||||
public void testSafecast() throws Exception {
|
public void testSafecast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
||||||
|
|||||||
Generated
+5
@@ -20592,6 +20592,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedTypeArgumentWithRecursion.kt")
|
||||||
|
public void testReifiedTypeArgumentWithRecursion() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithRecursion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("safecast.kt")
|
@TestMetadata("safecast.kt")
|
||||||
public void testSafecast() throws Exception {
|
public void testSafecast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
||||||
|
|||||||
+5
@@ -20652,6 +20652,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedTypeArgumentWithRecursion.kt")
|
||||||
|
public void testReifiedTypeArgumentWithRecursion() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithRecursion.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("safecast.kt")
|
@TestMetadata("safecast.kt")
|
||||||
public void testSafecast() throws Exception {
|
public void testSafecast() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
runTest("compiler/testData/codegen/box/reified/safecast.kt");
|
||||||
|
|||||||
+41
-23
@@ -27,12 +27,16 @@ object TypeOfFIF : FunctionIntrinsicFactory {
|
|||||||
object Intrinsic : FunctionIntrinsic() {
|
object Intrinsic : FunctionIntrinsic() {
|
||||||
override fun apply(callInfo: CallInfo, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
|
override fun apply(callInfo: CallInfo, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
|
||||||
val type = callInfo.resolvedCall.typeArguments.values.single()
|
val type = callInfo.resolvedCall.typeArguments.values.single()
|
||||||
return KTypeConstructor(context).createKType(type)
|
return context.createKType(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class KTypeConstructor(val context: TranslationContext) {
|
fun TranslationContext.createKType(type: KotlinType): JsExpression = KTypeConstructor(this).createKType(type)
|
||||||
|
|
||||||
|
private class KTypeConstructor(private val context: TranslationContext) {
|
||||||
|
private val visitedTypeParams = hashSetOf<TypeParameterDescriptor>()
|
||||||
|
|
||||||
fun callHelperFunction(name: String, vararg arguments: JsExpression) =
|
fun callHelperFunction(name: String, vararg arguments: JsExpression) =
|
||||||
JsInvocation(context.getReferenceToIntrinsic(name), *arguments)
|
JsInvocation(context.getReferenceToIntrinsic(name), *arguments)
|
||||||
|
|
||||||
@@ -92,7 +96,7 @@ class KTypeConstructor(val context: TranslationContext) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createKTypeProjection(tp: TypeProjection): JsExpression {
|
private fun createKTypeProjection(tp: TypeProjection): JsExpression {
|
||||||
if (tp.isStarProjection) {
|
if (tp.isStarProjection) {
|
||||||
return callHelperFunction(Namer.GET_START_KTYPE_PROJECTION)
|
return callHelperFunction(Namer.GET_START_KTYPE_PROJECTION)
|
||||||
}
|
}
|
||||||
@@ -108,32 +112,46 @@ class KTypeConstructor(val context: TranslationContext) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createKClassifier(classifier: ClassifierDescriptor): JsExpression =
|
private fun createKClassifier(classifier: ClassifierDescriptor): JsExpression =
|
||||||
when (classifier) {
|
when (classifier) {
|
||||||
is TypeParameterDescriptor -> createKTypeParameter(classifier)
|
is TypeParameterDescriptor -> createKTypeParameter(classifier, visitedTypeParams)
|
||||||
else -> ExpressionVisitor.getObjectKClass(context, classifier)
|
else -> ExpressionVisitor.getObjectKClass(context, classifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createKTypeParameter(typeParameter: TypeParameterDescriptor): JsExpression {
|
private fun createKTypeParameter(
|
||||||
val name = JsStringLiteral(typeParameter.name.asString())
|
typeParameter: TypeParameterDescriptor,
|
||||||
val upperBounds = JsArrayLiteral(typeParameter.upperBounds.map { createKType(it) })
|
visitedTypeParams: MutableSet<TypeParameterDescriptor>
|
||||||
val variance = when (typeParameter.variance) {
|
): JsExpression {
|
||||||
Variance.INVARIANT -> JsStringLiteral("invariant")
|
fun createKTypeParameterImpl(): JsExpression {
|
||||||
Variance.IN_VARIANCE -> JsStringLiteral("in")
|
val name = JsStringLiteral(typeParameter.name.asString())
|
||||||
Variance.OUT_VARIANCE -> JsStringLiteral("out")
|
val upperBounds = JsArrayLiteral(typeParameter.upperBounds.map { createKType(it) })
|
||||||
}
|
val variance = when (typeParameter.variance) {
|
||||||
if (typeParameter.isReified) {
|
//// TODO use consts, enums, numbers???
|
||||||
val kClassName = context.getNameForIntrinsic(SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE.suggestedName)
|
Variance.INVARIANT -> JsStringLiteral("invariant")
|
||||||
kClassName.specialFunction = SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
|
Variance.IN_VARIANCE -> JsStringLiteral("in")
|
||||||
|
Variance.OUT_VARIANCE -> JsStringLiteral("out")
|
||||||
|
}
|
||||||
|
if (typeParameter.isReified) {
|
||||||
|
val kClassName = context.getNameForIntrinsic(SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE.suggestedName)
|
||||||
|
kClassName.specialFunction = SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
|
||||||
|
|
||||||
return JsInvocation(kClassName.makeRef(), getReferenceToJsClass(typeParameter, context))
|
return JsInvocation(kClassName.makeRef(), getReferenceToJsClass(typeParameter, context))
|
||||||
|
}
|
||||||
|
|
||||||
|
return callHelperFunction(
|
||||||
|
Namer.CREATE_KTYPE_PARAMETER,
|
||||||
|
name,
|
||||||
|
upperBounds,
|
||||||
|
variance
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return callHelperFunction(
|
if (typeParameter in visitedTypeParams) return callHelperFunction(Namer.GET_START_KTYPE_PROJECTION)
|
||||||
Namer.CREATE_KTYPE_PARAMETER,
|
|
||||||
name,
|
visitedTypeParams.add(typeParameter)
|
||||||
upperBounds,
|
|
||||||
variance
|
return createKTypeParameterImpl().also {
|
||||||
)
|
visitedTypeParams.remove(typeParameter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.js.translate.context.Namer
|
|||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor
|
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor
|
||||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed
|
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed
|
||||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.KTypeConstructor
|
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.createKType
|
||||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -128,7 +128,7 @@ fun <T, S> List<T>.splitToRanges(classifier: (T) -> S): List<Pair<List<T>, S>> {
|
|||||||
|
|
||||||
fun getReferenceToJsClass(type: KotlinType, context: TranslationContext): JsExpression =
|
fun getReferenceToJsClass(type: KotlinType, context: TranslationContext): JsExpression =
|
||||||
getReferenceToJsClassOrArray(type, context).also {
|
getReferenceToJsClassOrArray(type, context).also {
|
||||||
it.kType = KTypeConstructor(context).createKType(type)
|
it.kType = context.createKType(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getReferenceToJsClassOrArray(type: KotlinType, context: TranslationContext): JsExpression {
|
fun getReferenceToJsClassOrArray(type: KotlinType, context: TranslationContext): JsExpression {
|
||||||
|
|||||||
Reference in New Issue
Block a user