From 8d33de4297155ee50615a7314a8d2698343739e4 Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 30 Aug 2022 12:15:40 +0200 Subject: [PATCH] JVM: partially reify typeOf and signatures as soon as possible E.g. when substituting T -> Array, write the bytecode for the Array<...> part for typeOf. This fixes various issues where either Array nesting levels, nullability information (for typeOf), or entire reification markers were missing, causing incorrect outputs ranging from missing `?`s to missing `[]`s to just reified types not really being reified. ^KT-53761 Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 33 +--- .../jetbrains/kotlin/codegen/codegenUtil.kt | 20 +++ .../kotlin/codegen/inline/AsmTypeRemapper.kt | 14 +- .../codegen/inline/ReifiedTypeInliner.kt | 124 ++++++++------- .../kotlin/codegen/inline/TypeRemapper.kt | 24 ++- .../jetbrains/kotlin/codegen/inline/typeOf.kt | 145 +++++++----------- .../FirBlackBoxCodegenTestGenerated.java | 18 +++ .../backend/jvm/codegen/ExpressionCodegen.kt | 25 +-- .../kotlin/backend/jvm/intrinsics/TypeOf.kt | 10 +- .../typeOf/arrayOfNullableReified.kt | 21 +++ .../typeOf/reifiedAsNestedArgument.kt | 20 +++ .../codegen/box/reified/typeTokenWrapper.kt | 33 ++++ .../codegen/BlackBoxCodegenTestGenerated.java | 18 +++ .../IrBlackBoxCodegenTestGenerated.java | 18 +++ .../LightAnalysisModeTestGenerated.java | 15 ++ .../js/test/JsCodegenBoxTestGenerated.java | 12 ++ .../test/ir/IrJsCodegenBoxTestGenerated.java | 12 ++ .../IrCodegenBoxWasmTestGenerated.java | 10 ++ .../NativeCodegenBoxTestGenerated.java | 12 ++ .../ir/SerializationJvmIrIntrinsicSupport.kt | 2 + 20 files changed, 363 insertions(+), 223 deletions(-) create mode 100644 compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt create mode 100644 compiler/testData/codegen/box/reified/typeTokenWrapper.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 79afd49d484..bc9cdf2b790 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2928,33 +2928,12 @@ public class ExpressionCodegen extends KtVisitor impleme @NotNull CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall resolvedCall, @NotNull CallableDescriptor descriptor) { - Map typeArguments = getTypeArgumentsForResolvedCall(resolvedCall, descriptor); - - TypeParameterMappings mappings = new TypeParameterMappings<>(); - for (Map.Entry entry : typeArguments.entrySet()) { - TypeParameterDescriptor key = entry.getKey(); - KotlinType type = entry.getValue(); - - boolean isReified = key.isReified() || InlineUtil.isArrayConstructorWithLambda(resolvedCall.getResultingDescriptor()); - - Pair typeParameterAndReificationArgument = - extractReificationArgument(typeSystem, type); - if (typeParameterAndReificationArgument == null) { - KotlinType approximatedType = approximateCapturedType(type); - JvmSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE); - Type asmType = typeMapper.mapTypeArgument(approximatedType, signatureWriter); - - mappings.addParameterMappingToType( - key.getName().getIdentifier(), approximatedType, asmType, signatureWriter.toString(), isReified - ); - } - else { - mappings.addParameterMappingForFurtherReification( - key.getName().getIdentifier(), type, typeParameterAndReificationArgument.getSecond(), isReified - ); - } - } - + TypeParameterMappings mappings = new TypeParameterMappings<>( + typeSystem, + getTypeArgumentsForResolvedCall(resolvedCall, descriptor), + InlineUtil.isArrayConstructorWithLambda(resolvedCall.getResultingDescriptor()), + (KotlinType type, BothSignatureWriter sw) -> typeMapper.mapTypeArgument(approximateCapturedType(type), sw) + ); return getOrCreateCallGenerator(descriptor, resolvedCall.getCall().getCallElement(), mappings, false); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 69172f3f8ba..f5e5aec732c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_ASM_TYPE import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX import org.jetbrains.kotlin.codegen.inline.ReificationArgument +import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper @@ -386,6 +387,7 @@ fun TypeSystemCommonBackendContext.extractReificationArgument(initialType: Kotli val isNullable = type.isMarkedNullable() while (type.isArrayOrNullableArray()) { arrayDepth++ + // TODO: warn that nullability info on argument will be lost? val argument = type.getArgument(0) if (argument.isStarProjection()) return null type = argument.getType() @@ -396,6 +398,24 @@ fun TypeSystemCommonBackendContext.extractReificationArgument(initialType: Kotli return Pair(typeParameter, ReificationArgument(typeParameter.getName().asString(), isNullable, arrayDepth)) } +fun TypeSystemCommonBackendContext.extractUsedReifiedParameters(type: KotlinTypeMarker): ReifiedTypeParametersUsages = + ReifiedTypeParametersUsages().apply { + fun KotlinTypeMarker.visit() { + val typeParameter = typeConstructor().getTypeParameterClassifier() + if (typeParameter == null) { + for (argument in getArguments()) { + if (!argument.isStarProjection()) { + argument.getType().visit() + } + } + } else if (typeParameter.isReified()) { + addUsedReifiedParameter(typeParameter.getName().asString()) + } + } + + type.visit() + } + fun unwrapInitialSignatureDescriptor(function: FunctionDescriptor): FunctionDescriptor = function.initialSignatureDescriptor ?: function diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AsmTypeRemapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AsmTypeRemapper.kt index 6e8d7277721..d255e939e2f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AsmTypeRemapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AsmTypeRemapper.kt @@ -30,16 +30,16 @@ class AsmTypeRemapper(val typeRemapper: TypeRemapper, val result: InlineResult) return object : SignatureRemapper(v, this) { override fun visitTypeVariable(name: String) { /*TODO try to erase absent type variable*/ - val mapping = typeRemapper.mapTypeParameter(name) ?: return super.visitTypeVariable(name) - - if (mapping.newName != null) { + val mapping = typeRemapper.mapTypeParameter(name) + if (mapping != null) { + // TODO: what is this condition if (mapping.isReified) { - result.reifiedTypeParametersUsages.addUsedReifiedParameter(mapping.newName) + result.reifiedTypeParametersUsages.mergeAll(mapping.reifiedTypeParametersUsages) } - return super.visitTypeVariable(mapping.newName) + SignatureReader(mapping.signature).accept(v) + return } - // else TypeVariable is replaced by concrete type - SignatureReader(mapping.signature).accept(v) + return super.visitTypeVariable(name) } override fun visitFormalTypeParameter(name: String) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index a4a89195eaa..4a3451afe59 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -5,10 +5,13 @@ package org.jetbrains.kotlin.codegen.inline +import org.jetbrains.kotlin.codegen.extractReificationArgument +import org.jetbrains.kotlin.codegen.extractUsedReifiedParameters import org.jetbrains.kotlin.codegen.generateAsCast import org.jetbrains.kotlin.codegen.generateIsCheck import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.optimization.common.intConstant +import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.name.Name @@ -147,9 +150,9 @@ class ReifiedTypeInliner( val result = ReifiedTypeParametersUsages() for (insn in instructions.toArray()) { if (isOperationReifiedMarker(insn)) { - val newName: String? = processReifyMarker(insn as MethodInsnNode, instructions) - if (newName != null) { - result.addUsedReifiedParameter(newName) + val newNames = processReifyMarker(insn as MethodInsnNode, instructions) + if (newNames != null) { + result.mergeAll(newNames) } } } @@ -158,33 +161,34 @@ class ReifiedTypeInliner( return result } - /** - * @return new type parameter identifier if this marker should be reified further - * or null if it shouldn't - */ - private fun processReifyMarker(insn: MethodInsnNode, instructions: InsnList): String? { + private fun processReifyMarker(insn: MethodInsnNode, instructions: InsnList): ReifiedTypeParametersUsages? { val operationKind = insn.operationKind ?: return null val reificationArgument = insn.reificationArgument ?: return null val mapping = parametersMapping?.get(reificationArgument.parameterName) ?: return null - if (mapping.asmType != null) { - // process* methods return false if marker should be reified further - // or it's invalid (may be emitted explicitly in code) - // they return true if instruction is reified and marker can be deleted - val (asmType, type) = reify(reificationArgument, mapping.asmType, mapping.type) - - val kotlinType = intrinsicsSupport.toKotlinType(type) - - var processed = if (isPluginNext(insn)) processPlugin(insn, instructions, type) else false - - if (!processed) processed = when (operationKind) { + val asmType = mapping.asmType.reify(reificationArgument) + val type = mapping.type.reify(reificationArgument) + // Runtime-available types on the JVM are: + // 1. Array for some runtime-available type T + // 2. C<*, ...> and C<*, ...>? for some classifier C + // `typeOf`-like intrinsics are special in that they can handle a bigger set of types, including + // 1. Array where T is not nullable + // 2. C with non-star projections A, B, ... + // To properly support those cases, we need to partially reify them even if we don't know the entire type yet. + // Otherwise nullability on all but the innermost dimension of a multidimensional array will be lost, + // and reified type parameters used as arguments to classifier types will never be reified. + if (mapping.reificationArgument == null || operationKind == OperationKind.TYPE_OF) { + val processed = (isPluginNext(insn) && processPlugin(insn, instructions, type)) || when (operationKind) { + // TODO: if `process*` returns false, then the marked sequence is invalid - simply leaving the marker in place + // will lead to an exception at runtime. What to do instead? Possible that the bytecode has been removed by + // dead code elimination (e.g. result of `T::class.java` was unused) and now we only need to erase the marker. OperationKind.NEW_ARRAY -> processNewArray(insn, asmType) - OperationKind.AS -> processAs(insn, instructions, kotlinType, asmType, safe = false) - OperationKind.SAFE_AS -> processAs(insn, instructions, kotlinType, asmType, safe = true) - OperationKind.IS -> processIs(insn, instructions, kotlinType, asmType) + OperationKind.AS -> processAs(insn, instructions, type, asmType, safe = false) + OperationKind.SAFE_AS -> processAs(insn, instructions, type, asmType, safe = true) + OperationKind.IS -> processIs(insn, instructions, type, asmType) OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType) OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType) - OperationKind.TYPE_OF -> processTypeOfOrPlugin(insn, instructions, type) + OperationKind.TYPE_OF -> processTypeOf(insn, instructions, type) } if (processed) { @@ -192,24 +196,22 @@ class ReifiedTypeInliner( instructions.remove(insn.previous!!) // PUSH type parameter instructions.remove(insn) // INVOKESTATIC marker method } - - return null } else { - val newReificationArgument = reificationArgument.combine(mapping.reificationArgument!!) + val newReificationArgument = reificationArgument.combine(mapping.reificationArgument) instructions.set(insn.previous!!, LdcInsnNode(newReificationArgument.asString())) - return mapping.reificationArgument.parameterName } + return mapping.reifiedTypeParametersUsages } - private fun reify(argument: ReificationArgument, replacementAsmType: Type, type: KT): Pair = + @Suppress("UNCHECKED_CAST") + private fun KT.reify(argument: ReificationArgument): KT = with(typeSystem) { - val arrayType = type.arrayOf(argument.arrayDepth) - @Suppress("UNCHECKED_CAST") - Pair( - Type.getType("[".repeat(argument.arrayDepth) + replacementAsmType), - (if (argument.nullable) arrayType.makeNullable() else arrayType) as KT - ) - } + val withArrays = arrayOf(argument.arrayDepth) + if (argument.nullable) withArrays.makeNullable() else withArrays + } as KT + + private fun Type.reify(argument: ReificationArgument): Type = + Type.getType("[".repeat(argument.arrayDepth) + this) private fun KotlinTypeMarker.arrayOf(arrayDepth: Int): KotlinTypeMarker { var currentType = this @@ -228,14 +230,14 @@ class ReifiedTypeInliner( private fun processAs( insn: MethodInsnNode, instructions: InsnList, - kotlinType: KotlinType, + type: KT, asmType: Type, safe: Boolean ) = rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { stubCheckcast: AbstractInsnNode -> if (stubCheckcast !is TypeInsnNode) return false val newMethodNode = MethodNode(Opcodes.API_VERSION) - generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, unifiedNullChecks) + generateAsCast(InstructionAdapter(newMethodNode), intrinsicsSupport.toKotlinType(type), asmType, safe, unifiedNullChecks) instructions.insert(insn, newMethodNode.instructions) // Keep stubCheckcast to avoid VerifyErrors on 1.8+ bytecode, @@ -253,13 +255,13 @@ class ReifiedTypeInliner( private fun processIs( insn: MethodInsnNode, instructions: InsnList, - kotlinType: KotlinType, + type: KT, asmType: Type ) = rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { stubInstanceOf: AbstractInsnNode -> if (stubInstanceOf !is TypeInsnNode) return false val newMethodNode = MethodNode(Opcodes.API_VERSION) - generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType) + generateIsCheck(InstructionAdapter(newMethodNode), intrinsicsSupport.toKotlinType(type), asmType) instructions.insert(insn, newMethodNode.instructions) instructions.remove(stubInstanceOf) @@ -269,7 +271,7 @@ class ReifiedTypeInliner( return true } - private fun processTypeOfOrPlugin( + private fun processTypeOf( insn: MethodInsnNode, instructions: InsnList, type: KT @@ -385,37 +387,43 @@ val MethodInsnNode.operationKind: ReifiedTypeInliner.OperationKind? ReifiedTypeInliner.OperationKind.values().getOrNull(it) } -class TypeParameterMappings { +class TypeParameterMappings( + typeSystem: TypeSystemCommonBackendContext, + typeArguments: Map, + allReified: Boolean, + mapType: (KT, BothSignatureWriter) -> Type +) { private val mappingsByName = hashMapOf>() - fun addParameterMappingToType(name: String, type: KT, asmType: Type, signature: String, isReified: Boolean) { - mappingsByName[name] = TypeParameterMapping( - name, type, asmType, reificationArgument = null, signature = signature, isReified = isReified - ) - } - - fun addParameterMappingForFurtherReification(name: String, type: KT, reificationArgument: ReificationArgument, isReified: Boolean) { - mappingsByName[name] = TypeParameterMapping( - name, type, asmType = null, reificationArgument = reificationArgument, signature = null, isReified = isReified - ) + init { + with(typeSystem) { + for ((parameter, type) in typeArguments.entries) { + val name = parameter.getName().identifier + val sw = BothSignatureWriter(BothSignatureWriter.Mode.TYPE) + mappingsByName[name] = TypeParameterMapping( + type, mapType(type, sw), sw.toString(), allReified || parameter.isReified(), + typeSystem.extractReificationArgument(type)?.second, + typeSystem.extractUsedReifiedParameters(type) + ) + } + } } operator fun get(name: String): TypeParameterMapping? = mappingsByName[name] fun hasReifiedParameters() = mappingsByName.values.any { it.isReified } - internal inline fun forEach(l: (TypeParameterMapping) -> Unit) { - mappingsByName.values.forEach(l) - } + internal inline fun forEach(block: (String, TypeParameterMapping) -> Unit) = + mappingsByName.entries.forEach { (name, mapping) -> block(name, mapping) } } class TypeParameterMapping( - val name: String, val type: KT, - val asmType: Type?, + val asmType: Type, + val signature: String, + val isReified: Boolean, val reificationArgument: ReificationArgument?, - val signature: String?, - val isReified: Boolean + val reifiedTypeParametersUsages: ReifiedTypeParametersUsages, ) class ReifiedTypeParametersUsages { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TypeRemapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TypeRemapper.kt index ea125005af6..bbed62f9483 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TypeRemapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TypeRemapper.kt @@ -18,8 +18,6 @@ package org.jetbrains.kotlin.codegen.inline import java.util.* -class TypeParameter(val oldName: String, val newName: String?, val isReified: Boolean, val signature: String?) - //typeMapping data could be changed outside through method processing class TypeRemapper private constructor( private val typeMapping: MutableMap, @@ -27,7 +25,7 @@ class TypeRemapper private constructor( private val isRootInlineLambda: Boolean = false ) { private val additionalMappings = hashMapOf() - private val typeParametersMapping = hashMapOf() + private val typeParametersMapping = hashMapOf?>() fun addMapping(type: String, newType: String) { typeMapping[type] = newType @@ -50,26 +48,24 @@ class TypeRemapper private constructor( // assert(typeParametersMapping[name] == null) { // "Type parameter already registered $name" // } - typeParametersMapping[name] = TypeParameter(name, name, false, null) + typeParametersMapping[name] = null } - fun registerTypeParameter(mapping: TypeParameterMapping<*>) { - typeParametersMapping[mapping.name] = TypeParameter( - mapping.name, mapping.reificationArgument?.parameterName, mapping.isReified, mapping.signature - ) + fun registerTypeParameter(name: String, mapping: TypeParameterMapping<*>) { + typeParametersMapping[name] = mapping } - fun mapTypeParameter(name: String): TypeParameter? { - return typeParametersMapping[name] ?: if (!isRootInlineLambda) parent?.mapTypeParameter(name) else null + fun mapTypeParameter(name: String): TypeParameterMapping<*>? = when { + name in typeParametersMapping -> typeParametersMapping[name] + !isRootInlineLambda -> parent?.mapTypeParameter(name) + else -> null } companion object { @JvmStatic - fun createRoot(formalTypeParameters: TypeParameterMappings<*>?): TypeRemapper { + fun createRoot(formalTypeParameters: TypeParameterMappings<*>): TypeRemapper { return TypeRemapper(HashMap()).apply { - formalTypeParameters?.forEach { - registerTypeParameter(it) - } + formalTypeParameters.forEach(::registerTypeParameter) } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt index 47ffb6e100f..1643b615f42 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt @@ -22,73 +22,62 @@ import kotlin.reflect.KVariance internal fun TypeSystemCommonBackendContext.createTypeOfMethodBody(typeParameter: TypeParameterMarker): MethodNode { val node = MethodNode(Opcodes.API_VERSION, Opcodes.ACC_STATIC, "fake", Type.getMethodDescriptor(K_TYPE), null, null) val v = InstructionAdapter(node) - - putTypeOfReifiedTypeParameter(v, typeParameter, false) + val argument = ReificationArgument(typeParameter.getName().asString(), false, 0) + ReifiedTypeInliner.putReifiedOperationMarker(ReifiedTypeInliner.OperationKind.TYPE_OF, argument, v) + v.aconst(null) v.areturn(K_TYPE) - v.visitMaxs(2, 0) - return node } -private fun TypeSystemCommonBackendContext.putTypeOfReifiedTypeParameter( - v: InstructionAdapter, typeParameter: TypeParameterMarker, isNullable: Boolean -) { - ReifiedTypeInliner.putReifiedOperationMarkerIfNeeded(typeParameter, isNullable, ReifiedTypeInliner.OperationKind.TYPE_OF, v, this) - v.aconst(null) +private inline fun InstructionAdapter.unrollArrayIfFewerThan(n: Int, limit: Int, type: Type, element: (Int) -> Unit): Array { + if (n < limit) { + return Array(n) { i -> + element(i) + type + } + } + iconst(n) + newarray(type) + for (i in 0 until n) { + dup() + iconst(i) + element(i) + astore(type) + } + return arrayOf(AsmUtil.getArrayType(type)) } fun TypeSystemCommonBackendContext.generateTypeOf( v: InstructionAdapter, type: KT, intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport +) = generateTypeOf(v, type, intrinsicsSupport, isTypeParameterBound = false) + +private fun TypeSystemCommonBackendContext.generateTypeOf( + v: InstructionAdapter, type: KT, intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport, isTypeParameterBound: Boolean ) { val typeParameter = type.typeConstructor().getTypeParameterClassifier() - if (typeParameter != null) { - if (!doesTypeContainTypeParametersWithRecursiveBounds(type)) { - intrinsicsSupport.reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameter.getName()) - v.aconst(null) - return - } - - generateNonReifiedTypeParameter(v, typeParameter, intrinsicsSupport) - } else { + val methodArguments = if (typeParameter == null) { intrinsicsSupport.putClassInstance(v, type) - } - - val argumentsSize = type.argumentsCount() - val useArray = argumentsSize >= 3 - - if (useArray) { - v.iconst(argumentsSize) - v.newarray(K_TYPE_PROJECTION) - } - - for (i in 0 until argumentsSize) { - if (useArray) { - v.dup() - v.iconst(i) - } - - doGenerateTypeProjection(v, type.getArgument(i), intrinsicsSupport) - - if (useArray) { - v.astore(K_TYPE_PROJECTION) + val arguments = v.unrollArrayIfFewerThan(type.argumentsCount(), 3, K_TYPE_PROJECTION) { i -> + generateTypeOfArgument(v, type.getArgument(i), intrinsicsSupport, isTypeParameterBound) } + arrayOf(JAVA_CLASS_TYPE, *arguments) + } else if (!isTypeParameterBound && typeParameter.isReified()) { + val argument = ReificationArgument(typeParameter.getName().asString(), type.isMarkedNullable(), 0) + ReifiedTypeInliner.putReifiedOperationMarker(ReifiedTypeInliner.OperationKind.TYPE_OF, argument, v) + v.aconst(null) + return + } else if (typeReferencesParameterWithRecursiveBound(type)) { + intrinsicsSupport.reportNonReifiedTypeParameterWithRecursiveBoundUnsupported(typeParameter.getName()) + v.aconst(null) + return + } else { + generateNonReifiedTypeParameter(v, typeParameter, intrinsicsSupport) + arrayOf(K_CLASSIFIER_TYPE) } val methodName = if (type.isMarkedNullable()) "nullableTypeOf" else "typeOf" - - val signature = if (typeParameter != null) { - Type.getMethodDescriptor(K_TYPE, K_CLASSIFIER_TYPE) - } else { - val projections = when (argumentsSize) { - 0 -> emptyArray() - 1 -> arrayOf(K_TYPE_PROJECTION) - 2 -> arrayOf(K_TYPE_PROJECTION, K_TYPE_PROJECTION) - else -> arrayOf(AsmUtil.getArrayType(K_TYPE_PROJECTION)) - } - Type.getMethodDescriptor(K_TYPE, JAVA_CLASS_TYPE, *projections) - } - + val signature = Type.getMethodDescriptor(K_TYPE, *methodArguments) v.invokestatic(REFLECTION, methodName, signature, false) if (intrinsicsSupport.toKotlinType(type).isSuspendFunctionType) { @@ -106,7 +95,7 @@ fun TypeSystemCommonBackendContext.generateTypeOf( // If this is a flexible type, we've just generated its lower bound and have it on the stack. // Let's generate the upper bound now and call the method that takes lower and upper bound and constructs a flexible KType. @Suppress("UNCHECKED_CAST") - generateTypeOf(v, type.upperBoundIfFlexible() as KT, intrinsicsSupport) + generateTypeOf(v, type.upperBoundIfFlexible() as KT, intrinsicsSupport, isTypeParameterBound) v.invokestatic(REFLECTION, "platformType", Type.getMethodDescriptor(K_TYPE, K_TYPE, K_TYPE), false) } @@ -132,76 +121,54 @@ private fun TypeSystemCommonBackendContext.generateNonRe false, ) - @Suppress("UNCHECKED_CAST") - val bounds = (0 until typeParameter.upperBoundCount()).map { typeParameter.getUpperBound(it) as KT } - if (bounds.isEmpty()) return + if (typeParameter.upperBoundCount() == 0) return v.dup() - - if (bounds.size == 1) { - generateTypeOf(v, bounds.single(), intrinsicsSupport) - } else { - v.iconst(bounds.size) - v.newarray(K_TYPE) - for ((i, bound) in bounds.withIndex()) { - v.dup() - v.iconst(i) - generateTypeOf(v, bound, intrinsicsSupport) - v.astore(K_TYPE) - } + val argumentsForBounds = v.unrollArrayIfFewerThan(typeParameter.upperBoundCount(), 2, K_TYPE) { i -> + @Suppress("UNCHECKED_CAST") + generateTypeOf(v, typeParameter.getUpperBound(i) as KT, intrinsicsSupport, isTypeParameterBound = true) } - v.invokestatic( - REFLECTION, "setUpperBounds", Type.getMethodDescriptor( - Type.VOID_TYPE, K_TYPE_PARAMETER, - if (bounds.size == 1) K_TYPE else AsmUtil.getArrayType(K_TYPE) - ), + REFLECTION, "setUpperBounds", Type.getMethodDescriptor(Type.VOID_TYPE, K_TYPE_PARAMETER, *argumentsForBounds), false ) } -private fun TypeSystemCommonBackendContext.doesTypeContainTypeParametersWithRecursiveBounds( +private fun TypeSystemCommonBackendContext.typeReferencesParameterWithRecursiveBound( type: KotlinTypeMarker, used: MutableSet = linkedSetOf() ): Boolean { val typeParameter = type.typeConstructor().getTypeParameterClassifier() if (typeParameter != null) { - if (!used.add(typeParameter)) return false + if (!used.add(typeParameter)) return true for (i in 0 until typeParameter.upperBoundCount()) { - if (!doesTypeContainTypeParametersWithRecursiveBounds(typeParameter.getUpperBound(i), used)) return false + if (typeReferencesParameterWithRecursiveBound(typeParameter.getUpperBound(i), used)) return true } used.remove(typeParameter) } else { for (i in 0 until type.argumentsCount()) { val argument = type.getArgument(i) - if (!argument.isStarProjection() && !doesTypeContainTypeParametersWithRecursiveBounds(argument.getType(), used)) return false + if (!argument.isStarProjection() && typeReferencesParameterWithRecursiveBound(argument.getType(), used)) return true } } - return true + return false } -private fun TypeSystemCommonBackendContext.doGenerateTypeProjection( +private fun TypeSystemCommonBackendContext.generateTypeOfArgument( v: InstructionAdapter, projection: TypeArgumentMarker, - intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport + intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport, + isTypeParameterBound: Boolean, ) { - // KTypeProjection members could be static, see KT-30083 and KT-30084 + // KTypeProjection companion members could be made `@JvmStatic`, see KT-30083 and KT-30084 v.getstatic(K_TYPE_PROJECTION.internalName, "Companion", K_TYPE_PROJECTION_COMPANION.descriptor) - if (projection.isStarProjection()) { v.invokevirtual(K_TYPE_PROJECTION_COMPANION.internalName, "getSTAR", Type.getMethodDescriptor(K_TYPE_PROJECTION), false) return } @Suppress("UNCHECKED_CAST") - val type = projection.getType() as KT - val typeParameterClassifier = type.typeConstructor().getTypeParameterClassifier() - if (typeParameterClassifier != null && typeParameterClassifier.isReified()) { - putTypeOfReifiedTypeParameter(v, typeParameterClassifier, type.isMarkedNullable()) - } else { - generateTypeOf(v, type, intrinsicsSupport) - } - + generateTypeOf(v, projection.getType() as KT, intrinsicsSupport, isTypeParameterBound) val methodName = when (projection.getVariance()) { TypeVariance.INV -> "invariant" TypeVariance.IN -> "contravariant" diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 0efc0bf8cb6..9e441406cf8 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -44586,6 +44586,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reflection/typeOf/annotatedType.kt"); } + @Test + @TestMetadata("arrayOfNullableReified.kt") + public void testArrayOfNullableReified() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt"); + } + @Test @TestMetadata("caching.kt") public void testCaching() throws Exception { @@ -44676,6 +44682,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reflection/typeOf/rawTypes_before.kt"); } + @Test + @TestMetadata("reifiedAsNestedArgument.kt") + public void testReifiedAsNestedArgument() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt"); + } + @Test @TestMetadata("typeOfCapturedStar.kt") public void testTypeOfCapturedStar() throws Exception { @@ -45989,6 +46001,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reified/spreads.kt"); } + @Test + @TestMetadata("typeTokenWrapper.kt") + public void testTypeTokenWrapper() throws Exception { + runTest("compiler/testData/codegen/box/reified/typeTokenWrapper.kt"); + } + @Test @TestMetadata("varargs.kt") public void testVarargs() throws Exception { diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 52ffc12aa51..3e2253e62bd 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -57,7 +57,6 @@ import org.jetbrains.kotlin.types.computeExpandedTypeForInlineClass import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs -import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type @@ -1455,30 +1454,12 @@ class ExpressionCodegen( if (element.typeArgumentsCount == 0) { //avoid ambiguity with type constructor type parameters emptyMap() - } else typeArgumentContainer.typeParameters.keysToMap { - element.getTypeArgumentOrDefault(it) + } else typeArgumentContainer.typeParameters.associate { + it.symbol to element.getTypeArgumentOrDefault(it) } - val mappings = TypeParameterMappings() - for ((key, type) in typeArguments.entries) { - val reificationArgument = typeMapper.typeSystem.extractReificationArgument(type) - if (reificationArgument == null) { - // type is not generic - val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE) - val asmType = typeMapper.mapTypeParameter(type, signatureWriter) - - mappings.addParameterMappingToType( - key.name.identifier, type, asmType, signatureWriter.toString(), key.isReified - ) - } else { - mappings.addParameterMappingForFurtherReification( - key.name.identifier, type, reificationArgument.second, key.isReified - ) - } - } - + val mappings = TypeParameterMappings(typeMapper.typeSystem, typeArguments, allReified = false, typeMapper::mapTypeParameter) val sourceCompiler = IrSourceCompilerForInline(state, element, callee, this, data) - val reifiedTypeInliner = ReifiedTypeInliner( mappings, IrInlineIntrinsicsSupport(classCodegen, element, irFunction.fileParent), diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt index 62e1165f020..2523547530d 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.backend.jvm.codegen.IrInlineIntrinsicsSupport import org.jetbrains.kotlin.backend.jvm.ir.fileParent +import org.jetbrains.kotlin.codegen.extractUsedReifiedParameters import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner import org.jetbrains.kotlin.codegen.inline.generateTypeOf import org.jetbrains.kotlin.codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter @@ -17,12 +18,9 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression object TypeOf : IntrinsicMethod() { override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo) = with(codegen) { val type = expression.getTypeArgument(0)!! - if (putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.TYPE_OF)) { - mv.aconst(null) // see ReifiedTypeInliner.processTypeOf - } else { - val support = IrInlineIntrinsicsSupport(codegen.classCodegen, expression, codegen.irFunction.fileParent) - typeMapper.typeSystem.generateTypeOf(mv, type, support) - } + val support = IrInlineIntrinsicsSupport(codegen.classCodegen, expression, codegen.irFunction.fileParent) + typeMapper.typeSystem.generateTypeOf(mv, type, support) + codegen.propagateChildReifiedTypeParametersUsages(codegen.typeMapper.typeSystem.extractUsedReifiedParameters(type)) expression.onStack } } diff --git a/compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt b/compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt new file mode 100644 index 00000000000..c6de4cdcf6d --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt @@ -0,0 +1,21 @@ +// IGNORE_BACKEND: JS_IR, JS_IR_ES6 +// WITH_REFLECT + +import kotlin.reflect.typeOf +import kotlin.test.assertEquals + +inline fun typeOfArrayOfNArrayOf() = + typeOf?>>() + +inline fun myTypeOf() = + typeOf() + +inline fun myTypeOfArrayOfNArrayOf() = + typeOf?>>() + +fun box(): String { + assertEquals(typeOf?>>(), typeOfArrayOfNArrayOf()) + assertEquals(typeOf?>>(), myTypeOf?>>()) + assertEquals(typeOf?>>(), myTypeOfArrayOfNArrayOf()) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt b/compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt new file mode 100644 index 00000000000..cea503b36f2 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt @@ -0,0 +1,20 @@ +// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6 +// WITH_REFLECT + +import kotlin.reflect.typeOf +import kotlin.reflect.KType +import kotlin.test.assertEquals + +inline fun foo() = + object { val x = typeOf() }.x + +inline fun bar(expected: KType) { + assertEquals(expected, foo>()) + assertEquals(expected, object { val x = typeOf>() }.x) + assertEquals(expected, typeOf>()) +} + +fun box(): String { + bar(typeOf>()) + return "OK" +} diff --git a/compiler/testData/codegen/box/reified/typeTokenWrapper.kt b/compiler/testData/codegen/box/reified/typeTokenWrapper.kt new file mode 100644 index 00000000000..ae7ddcbd2c9 --- /dev/null +++ b/compiler/testData/codegen/box/reified/typeTokenWrapper.kt @@ -0,0 +1,33 @@ +// TARGET_BACKEND: JVM +// ISSUE: KT-53761 +// WITH_STDLIB +// IGNORE_BACKEND: ANDROID + +import kotlin.test.assertEquals + +open class TypeToken { + val type = javaClass.genericSuperclass +} + +inline fun myTypeOf() = + object : TypeToken() {}.type + +inline fun myTypeOfArrayOf() = + object : TypeToken>() {}.type + +inline fun myTypeOfArrayOf2() = + myTypeOf>() + +inline fun myTypeOfListOf() = + object : TypeToken>() {}.type + +inline fun myTypeOfListOf2() = + myTypeOf>() + +fun box(): String { + assertEquals(myTypeOf>(), myTypeOfArrayOf()) + assertEquals(myTypeOf>(), myTypeOfArrayOf2()) + assertEquals(myTypeOf>(), myTypeOfListOf()) + assertEquals(myTypeOf>(), myTypeOfListOf2()) + return "OK" +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 1b257ba97e6..57cffefec87 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -43104,6 +43104,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/typeOf/annotatedType.kt"); } + @Test + @TestMetadata("arrayOfNullableReified.kt") + public void testArrayOfNullableReified() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt"); + } + @Test @TestMetadata("classes.kt") public void testClasses() throws Exception { @@ -43188,6 +43194,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reflection/typeOf/rawTypes_before.kt"); } + @Test + @TestMetadata("reifiedAsNestedArgument.kt") + public void testReifiedAsNestedArgument() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt"); + } + @Test @TestMetadata("typeOfCapturedStar.kt") public void testTypeOfCapturedStar() throws Exception { @@ -44501,6 +44513,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reified/spreads.kt"); } + @Test + @TestMetadata("typeTokenWrapper.kt") + public void testTypeTokenWrapper() throws Exception { + runTest("compiler/testData/codegen/box/reified/typeTokenWrapper.kt"); + } + @Test @TestMetadata("varargs.kt") public void testVarargs() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 4a00392f65a..8ac5d4bf3a9 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -44586,6 +44586,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/typeOf/annotatedType.kt"); } + @Test + @TestMetadata("arrayOfNullableReified.kt") + public void testArrayOfNullableReified() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt"); + } + @Test @TestMetadata("caching.kt") public void testCaching() throws Exception { @@ -44676,6 +44682,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reflection/typeOf/rawTypes_before.kt"); } + @Test + @TestMetadata("reifiedAsNestedArgument.kt") + public void testReifiedAsNestedArgument() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt"); + } + @Test @TestMetadata("typeOfCapturedStar.kt") public void testTypeOfCapturedStar() throws Exception { @@ -45989,6 +46001,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reified/spreads.kt"); } + @Test + @TestMetadata("typeTokenWrapper.kt") + public void testTypeTokenWrapper() throws Exception { + runTest("compiler/testData/codegen/box/reified/typeTokenWrapper.kt"); + } + @Test @TestMetadata("varargs.kt") public void testVarargs() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 43a35d6fe21..eaa2d5448e8 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -34660,6 +34660,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/typeOf/annotatedType.kt"); } + @TestMetadata("arrayOfNullableReified.kt") + public void testArrayOfNullableReified() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt"); + } + @TestMetadata("classes.kt") public void testClasses() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt"); @@ -34730,6 +34735,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reflection/typeOf/rawTypes_before.kt"); } + @TestMetadata("reifiedAsNestedArgument.kt") + public void testReifiedAsNestedArgument() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt"); + } + @TestMetadata("typeOfCapturedStar.kt") public void testTypeOfCapturedStar() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/typeOfCapturedStar.kt"); @@ -35871,6 +35881,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reified/spreads.kt"); } + @TestMetadata("typeTokenWrapper.kt") + public void testTypeTokenWrapper() throws Exception { + runTest("compiler/testData/codegen/box/reified/typeTokenWrapper.kt"); + } + @TestMetadata("varargs.kt") public void testVarargs() throws Exception { runTest("compiler/testData/codegen/box/reified/varargs.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java index 25ab876d442..85cbd17b49c 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java @@ -32486,6 +32486,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); } + @Test + @TestMetadata("arrayOfNullableReified.kt") + public void testArrayOfNullableReified() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt"); + } + @Test @TestMetadata("classes.kt") public void testClasses() throws Exception { @@ -32516,6 +32522,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt"); } + @Test + @TestMetadata("reifiedAsNestedArgument.kt") + public void testReifiedAsNestedArgument() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt"); + } + @Test @TestMetadata("typeOfCapturedStar.kt") public void testTypeOfCapturedStar() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java index 87374184c06..9c3ae4395c8 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java @@ -32666,6 +32666,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); } + @Test + @TestMetadata("arrayOfNullableReified.kt") + public void testArrayOfNullableReified() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt"); + } + @Test @TestMetadata("classes.kt") public void testClasses() throws Exception { @@ -32696,6 +32702,12 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt"); } + @Test + @TestMetadata("reifiedAsNestedArgument.kt") + public void testReifiedAsNestedArgument() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt"); + } + @Test @TestMetadata("typeOfCapturedStar.kt") public void testTypeOfCapturedStar() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 696f31a9b23..fe017ad7db5 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/testOld/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -29295,6 +29295,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); } + @TestMetadata("arrayOfNullableReified.kt") + public void testArrayOfNullableReified() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt"); + } + @TestMetadata("classes.kt") public void testClasses() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt"); @@ -29320,6 +29325,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt"); } + @TestMetadata("reifiedAsNestedArgument.kt") + public void testReifiedAsNestedArgument() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt"); + } + @TestMetadata("typeOfCapturedStar.kt") public void testTypeOfCapturedStar() throws Exception { runTest("compiler/testData/codegen/box/reflection/typeOf/typeOfCapturedStar.kt"); diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java index e1e3021c440..012f44402d9 100644 --- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java +++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java @@ -35743,6 +35743,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true); } + @Test + @TestMetadata("arrayOfNullableReified.kt") + public void testArrayOfNullableReified() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/arrayOfNullableReified.kt"); + } + @Test @TestMetadata("classes.kt") public void testClasses() throws Exception { @@ -35773,6 +35779,12 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt"); } + @Test + @TestMetadata("reifiedAsNestedArgument.kt") + public void testReifiedAsNestedArgument() throws Exception { + runTest("compiler/testData/codegen/box/reflection/typeOf/reifiedAsNestedArgument.kt"); + } + @Test @TestMetadata("typeOfCapturedStar.kt") public void testTypeOfCapturedStar() throws Exception { diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt index 6dc2faf6ea8..c77605d683c 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerializationJvmIrIntrinsicSupport.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.backend.jvm.intrinsics.IntrinsicMethod import org.jetbrains.kotlin.backend.jvm.ir.representativeUpperBound import org.jetbrains.kotlin.backend.jvm.mapping.mapClass import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.extractUsedReifiedParameters import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.pluginIntrinsicsMarkerMethod import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.pluginIntrinsicsMarkerOwner @@ -92,6 +93,7 @@ class SerializationJvmIrIntrinsicSupport(val jvmBackendContext: JvmBackendContex mv, intrinsicType ) + codegen.propagateChildReifiedTypeParametersUsages(codegen.typeMapper.typeSystem.extractUsedReifiedParameters(argument)) if (withModule) { frameMap.leaveTemp(serializersModuleType) }