JVM IR: do not use old KotlinTypeMapper when coercing inline classes

KotlinTypeMapper.mapInlineClassTypeAsDeclaration and
mapUnderlyingTypeOfInlineClassType invoked mapType which is defined in
descriptorBasedTypeSignatureMapping.kt and works on KotlinType.

It didn't lead to any problems, other than the fact that we were
constructing IrBasedClassDescriptor in JVM IR, and then KotlinType to
pass it to mapType, on each call to StackValue.boxInlineClass or
unboxInlineClass, which seems wasteful.

Instead of this, refactor these utilities to use type markers instead,
pass IrType and IrTypeMapper directly from JVM IR, and move the "static
type mapper" logic (which is used only in the old backend) out of
KotlinTypeMapper.
This commit is contained in:
Alexander Udalov
2021-03-31 17:03:38 +02:00
parent b5ecccb610
commit b59ac5d8f6
16 changed files with 162 additions and 98 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.state.StaticTypeMapperForOldBackend
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -51,7 +52,7 @@ class CallableMethod(
override fun genInvokeInstruction(v: InstructionAdapter) {
if (boxInlineClassBeforeInvoke) {
StackValue.boxInlineClass(dispatchReceiverKotlinType!!, v)
StackValue.boxInlineClass(dispatchReceiverKotlinType!!, v, StaticTypeMapperForOldBackend)
}
v.visitMethodInsn(
invokeOpcode,
@@ -34,7 +34,8 @@ import org.jetbrains.org.objectweb.asm.commons.Method;
import java.util.List;
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
import static org.jetbrains.kotlin.codegen.AsmUtil.correctElementType;
import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.*;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_STRING_TYPE;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
@@ -306,7 +307,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
iv.load(secondParameterIndex, OBJECT_TYPE);
iv.checkcast(wrapperType);
StackValue.unboxInlineClass(wrapperType, wrapperKotlinType, iv);
StackValue.unboxInlineClass(wrapperType, wrapperKotlinType, iv, typeMapper);
iv.store(unboxedValueIndex, underlyingType.getType());
return unboxedValueIndex;
@@ -20,11 +20,14 @@ import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapperBase;
import org.jetbrains.kotlin.codegen.state.StaticTypeMapperForOldBackend;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.load.java.DescriptorsJvmAbiUtil;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.ValueArgument;
@@ -43,6 +46,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.SimpleType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.model.KotlinTypeMarker;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
@@ -452,11 +456,13 @@ public abstract class StackValue {
v.invokevirtual(methodOwner.getInternalName(), type.getClassName() + "Value", "()" + type.getDescriptor(), false);
}
public static void boxInlineClass(@NotNull KotlinType kotlinType, @NotNull InstructionAdapter v) {
Type boxedType = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(kotlinType);
Type underlyingType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType);
public static void boxInlineClass(
@NotNull KotlinTypeMarker kotlinType, @NotNull InstructionAdapter v, @NotNull KotlinTypeMapperBase typeMapper
) {
Type boxedType = typeMapper.mapTypeCommon(kotlinType, TypeMappingMode.CLASS_DECLARATION);
Type underlyingType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType, typeMapper);
if (TypeUtils.isNullableType(kotlinType) && !isPrimitive(underlyingType)) {
if (typeMapper.getTypeSystem().isNullableType(kotlinType) && !isPrimitive(underlyingType)) {
boxOrUnboxWithNullCheck(v, vv -> invokeBoxMethod(vv, boxedType, underlyingType));
}
else {
@@ -477,14 +483,19 @@ public abstract class StackValue {
);
}
public static void unboxInlineClass(@NotNull Type type, @NotNull KotlinType targetInlineClassType, @NotNull InstructionAdapter v) {
Type owner = KotlinTypeMapper.mapInlineClassTypeAsDeclaration(targetInlineClassType);
public static void unboxInlineClass(
@NotNull Type type,
@NotNull KotlinTypeMarker targetInlineClassType,
@NotNull InstructionAdapter v,
@NotNull KotlinTypeMapperBase typeMapper
) {
Type owner = typeMapper.mapTypeCommon(targetInlineClassType, TypeMappingMode.CLASS_DECLARATION);
coerce(type, owner, v);
Type resultType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(targetInlineClassType);
Type resultType = KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(targetInlineClassType, typeMapper);
if (TypeUtils.isNullableType(targetInlineClassType) && !isPrimitive(resultType)) {
if (typeMapper.getTypeSystem().isNullableType(targetInlineClassType) && !isPrimitive(resultType)) {
boxOrUnboxWithNullCheck(v, vv -> invokeUnboxMethod(vv, owner, resultType));
}
else {
@@ -537,7 +548,7 @@ public abstract class StackValue {
@Nullable KotlinType toKotlinType,
@NotNull InstructionAdapter v
) {
if (coerceInlineClasses(fromType, fromKotlinType, toType, toKotlinType, v)) return;
if (coerceInlineClasses(fromType, fromKotlinType, toType, toKotlinType, v, StaticTypeMapperForOldBackend.INSTANCE)) return;
coerce(fromType, toType, v);
}
@@ -573,7 +584,8 @@ public abstract class StackValue {
@Nullable KotlinType fromKotlinType,
@NotNull Type toType,
@Nullable KotlinType toKotlinType,
@NotNull InstructionAdapter v
@NotNull InstructionAdapter v,
@NotNull KotlinTypeMapperBase typeMapper
) {
// NB see also requiresInlineClassBoxingOrUnboxing above
@@ -600,23 +612,23 @@ public abstract class StackValue {
boolean isFromTypeUnboxed = isUnboxedInlineClass(fromKotlinType, fromType);
boolean isToTypeUnboxed = isUnboxedInlineClass(toKotlinType, toType);
if (isFromTypeUnboxed && !isToTypeUnboxed) {
boxInlineClass(fromKotlinType, v);
boxInlineClass(fromKotlinType, v, typeMapper);
return true;
}
else if (!isFromTypeUnboxed && isToTypeUnboxed) {
unboxInlineClass(fromType, toKotlinType, v);
unboxInlineClass(fromType, toKotlinType, v, typeMapper);
return true;
}
}
else if (isFromTypeInlineClass) {
if (isUnboxedInlineClass(fromKotlinType, fromType)) {
boxInlineClass(fromKotlinType, v);
boxInlineClass(fromKotlinType, v, typeMapper);
return true;
}
}
else { // isToTypeInlineClass is `true`
if (isUnboxedInlineClass(toKotlinType, toType)) {
unboxInlineClass(fromType, toKotlinType, v);
unboxInlineClass(fromType, toKotlinType, v, typeMapper);
return true;
}
}
@@ -625,7 +637,7 @@ public abstract class StackValue {
}
public static boolean isUnboxedInlineClass(@NotNull KotlinType kotlinType, @NotNull Type actualType) {
return KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType).equals(actualType);
return KotlinTypeMapper.mapUnderlyingTypeOfInlineClassType(kotlinType, StaticTypeMapperForOldBackend.INSTANCE).equals(actualType);
}
public static void coerce(@NotNull Type fromType, @NotNull Type toType, @NotNull InstructionAdapter v) {
@@ -44,7 +44,6 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.backend.common.SamType
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.MethodVisitor
@@ -451,7 +450,7 @@ class CoroutineCodegenForLambda private constructor(
if (parameter.type.isInlineClassType()) {
load(cloneIndex, fieldInfoForCoroutineLambdaParameter.ownerType)
load(index, AsmTypes.OBJECT_TYPE)
StackValue.unboxInlineClass(AsmTypes.OBJECT_TYPE, parameter.type, this)
StackValue.unboxInlineClass(AsmTypes.OBJECT_TYPE, parameter.type, this, typeMapper)
putfield(
fieldInfoForCoroutineLambdaParameter.ownerInternalName,
fieldInfoForCoroutineLambdaParameter.fieldName,
@@ -757,7 +756,7 @@ class CoroutineCodegenForNamedFunction private constructor(
generateCoroutineSuspendedCheck(languageVersionSettings)
// Now we box the inline class
StackValue.coerce(AsmTypes.OBJECT_TYPE, typeMapper.mapType(inlineClassToBoxInInvokeSuspend), this)
StackValue.boxInlineClass(inlineClassToBoxInInvokeSuspend, this)
StackValue.boxInlineClass(inlineClassToBoxInInvokeSuspend, this, typeMapper)
}
}
@@ -861,4 +860,4 @@ fun reportSuspensionPointInsideMonitor(element: KtElement, state: GenerationStat
}
private fun FunctionDescriptor.allValueParameterTypes(): List<KotlinType> =
(listOfNotNull(extensionReceiverParameter?.type)) + valueParameters.map { it.type }
(listOfNotNull(extensionReceiverParameter?.type)) + valueParameters.map { it.type }
@@ -7,8 +7,11 @@ package org.jetbrains.kotlin.codegen.inline
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.ASSERTIONS_DISABLED_FIELD_NAME
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.BaseExpressionCodegen
import org.jetbrains.kotlin.codegen.SamWrapperCodegen.SAM_WRAPPER_SUFFIX
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.context.CodegenContext
@@ -22,6 +25,7 @@ import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapperBase
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.load.java.JvmAbi
@@ -32,9 +36,9 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.*
@@ -415,13 +419,13 @@ fun addInlineMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
internal fun addUnboxInlineClassMarkersIfNeeded(v: InstructionAdapter, descriptor: CallableDescriptor, typeMapper: KotlinTypeMapper) {
val inlineClass = (descriptor as? FunctionDescriptor)?.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(typeMapper)
if (inlineClass != null) {
generateResumePathUnboxing(v, inlineClass)
generateResumePathUnboxing(v, inlineClass, typeMapper)
}
}
fun generateResumePathUnboxing(v: InstructionAdapter, inlineClass: KotlinType) {
fun generateResumePathUnboxing(v: InstructionAdapter, inlineClass: KotlinTypeMarker, typeMapper: KotlinTypeMapperBase) {
addBeforeUnboxInlineClassMarker(v)
StackValue.unboxInlineClass(AsmTypes.OBJECT_TYPE, inlineClass, v)
StackValue.unboxInlineClass(AsmTypes.OBJECT_TYPE, inlineClass, v, typeMapper)
// Suspend functions always returns Any?, but the unboxing disrupts type analysis of the bytecode.
// For example, if the underlying type is String, CHECKCAST String is removed.
// However, the unboxing is moved to the resume path, the direct path still has Any?, but now, without the CHECKCAST.
@@ -75,7 +75,6 @@ import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
import org.jetbrains.kotlin.types.checker.convertVariance
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.backend.common.SamType
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
@@ -101,6 +100,9 @@ class KotlinTypeMapper @JvmOverloads constructor(
field = value
}
override val typeSystem: TypeSystemCommonBackendContext
get() = SimpleClassicTypeSystemContext
private val typeMappingConfiguration = object : TypeMappingConfiguration<Type> {
override fun commonSupertype(types: Collection<KotlinType>): KotlinType {
return CommonSupertypes.commonSupertype(types)
@@ -233,6 +235,10 @@ class KotlinTypeMapper @JvmOverloads constructor(
return mapType(classifier.defaultType, null, TypeMappingMode.CLASS_DECLARATION)
}
override fun mapTypeCommon(type: KotlinTypeMarker, mode: TypeMappingMode): Type {
return mapType(type as KotlinType, null, mode)
}
fun mapTypeAsDeclaration(kotlinType: KotlinType): Type {
return mapType(kotlinType, null, TypeMappingMode.CLASS_DECLARATION)
}
@@ -1272,29 +1278,6 @@ class KotlinTypeMapper @JvmOverloads constructor(
}
companion object {
private val staticTypeMappingConfiguration = object : TypeMappingConfiguration<Type> {
override fun commonSupertype(types: Collection<KotlinType>): KotlinType {
return CommonSupertypes.commonSupertype(types)
}
override fun getPredefinedTypeForClass(classDescriptor: ClassDescriptor): Type? {
return null
}
override fun getPredefinedInternalNameForClass(classDescriptor: ClassDescriptor): String? {
return null
}
override fun processErrorType(kotlinType: KotlinType, descriptor: ClassDescriptor) {
throw IllegalStateException(generateErrorMessageForErrorType(kotlinType, descriptor))
}
override fun preprocessType(kotlinType: KotlinType): KotlinType? {
return null
}
}
/**
* Use proper LanguageVersionSettings where possible.
*/
@@ -1412,30 +1395,15 @@ class KotlinTypeMapper @JvmOverloads constructor(
return ContainingClassesInfo.forPackageMember(facadeName, implClassName)
}
// Make sure this method is called only from back-end
// It uses staticTypeMappingConfiguration that throws exception on error types
@JvmStatic
fun mapInlineClassTypeAsDeclaration(kotlinType: KotlinType): Type {
return mapInlineClassType(kotlinType, TypeMappingMode.CLASS_DECLARATION, staticTypeMappingConfiguration)
fun mapUnderlyingTypeOfInlineClassType(kotlinType: KotlinTypeMarker, typeMapper: KotlinTypeMapperBase): Type {
val underlyingType = with(typeMapper.typeSystem) {
kotlinType.getUnsubstitutedUnderlyingType()
} ?: throw IllegalStateException("There should be underlying type for inline class type: $kotlinType")
return typeMapper.mapTypeCommon(underlyingType, TypeMappingMode.DEFAULT)
}
// Make sure this method is called only from back-end
// It uses staticTypeMappingConfiguration that throws exception on error types
@JvmStatic
fun mapUnderlyingTypeOfInlineClassType(kotlinType: KotlinType): Type {
val underlyingType = kotlinType.unsubstitutedUnderlyingType()
?: throw IllegalStateException("There should be underlying type for inline class type: $kotlinType")
return mapInlineClassType(underlyingType, TypeMappingMode.DEFAULT, staticTypeMappingConfiguration)
}
private fun mapInlineClassType(
kotlinType: KotlinType,
mode: TypeMappingMode,
configuration: TypeMappingConfiguration<Type>
): Type =
mapType(kotlinType, AsmTypeFactory, mode, configuration, null)
private fun generateErrorMessageForErrorType(type: KotlinType, descriptor: DeclarationDescriptor): String {
internal fun generateErrorMessageForErrorType(type: KotlinType, descriptor: DeclarationDescriptor): String {
val declarationElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor)
?: return "Error type encountered: $type (${type.javaClass.simpleName})."
@@ -8,11 +8,18 @@ package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.org.objectweb.asm.Type
abstract class KotlinTypeMapperBase {
abstract val typeSystem: TypeSystemCommonBackendContext
abstract fun mapClass(classifier: ClassifierDescriptor): Type
abstract fun mapTypeCommon(type: KotlinTypeMarker, mode: TypeMappingMode): Type
fun mapDefaultImpls(descriptor: ClassDescriptor): Type =
Type.getObjectType(mapClass(descriptor).internalName + JvmAbi.DEFAULT_IMPLS_SUFFIX)
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2021 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.codegen.state
import org.jetbrains.kotlin.codegen.signature.AsmTypeFactory
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.load.kotlin.TypeMappingConfiguration
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.load.kotlin.mapType
import org.jetbrains.kotlin.types.CommonSupertypes
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.org.objectweb.asm.Type
// This class exists only because it's used to box/unbox inline classes in the static method StackValue.coerce in the old backend, which
// has no access to the correct type mapper instance, yet has a lot of call sites across the old backend, refactoring which would be costly.
object StaticTypeMapperForOldBackend : KotlinTypeMapperBase() {
override val typeSystem: TypeSystemCommonBackendContext
get() = SimpleClassicTypeSystemContext
private val staticTypeMappingConfiguration = object : TypeMappingConfiguration<Type> {
override fun commonSupertype(types: Collection<KotlinType>): KotlinType {
return CommonSupertypes.commonSupertype(types)
}
override fun getPredefinedTypeForClass(classDescriptor: ClassDescriptor): Type? {
return null
}
override fun getPredefinedInternalNameForClass(classDescriptor: ClassDescriptor): String? {
return null
}
override fun processErrorType(kotlinType: KotlinType, descriptor: ClassDescriptor) {
throw IllegalStateException(KotlinTypeMapper.generateErrorMessageForErrorType(kotlinType, descriptor))
}
override fun preprocessType(kotlinType: KotlinType): KotlinType? {
return null
}
}
override fun mapClass(classifier: ClassifierDescriptor): Type = TODO("Should not be called")
override fun mapTypeCommon(type: KotlinTypeMarker, mode: TypeMappingMode): Type {
return mapType(type as KotlinType, AsmTypeFactory, mode, staticTypeMappingConfiguration, null)
}
}
@@ -11,10 +11,19 @@ import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolved
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.fir.types.ConeTypeContext
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.types.model.typeConstructor
fun ConeKotlinType.substitutedUnderlyingTypeForInlineClass(session: FirSession, context: ConeTypeContext): ConeKotlinType? {
internal fun ConeKotlinType.substitutedUnderlyingTypeForInlineClass(session: FirSession, context: ConeTypeContext): ConeKotlinType? {
val unsubstitutedType = unsubstitutedUnderlyingTypeForInlineClass(session) ?: return null
val substitutor = createTypeSubstitutorByTypeConstructor(mapOf(this.typeConstructor(context) to this), context)
return substitutor.substituteOrNull(unsubstitutedType)
}
internal fun ConeKotlinType.unsubstitutedUnderlyingTypeForInlineClass(session: FirSession): ConeKotlinType? {
val symbol = (this.fullyExpandedType(session) as? ConeLookupTagBasedType)
?.lookupTag
?.toSymbol(session) as? FirRegularClassSymbol
@@ -24,8 +33,5 @@ fun ConeKotlinType.substitutedUnderlyingTypeForInlineClass(session: FirSession,
if (!firClass.status.isInline) return null
val constructor = firClass.declarations.singleOrNull { it is FirConstructor && it.isPrimary } as FirConstructor? ?: return null
val valueParameter = constructor.valueParameters.singleOrNull() ?: return null
val unsubstitutedType = valueParameter.returnTypeRef.coneType
val substitutor = createTypeSubstitutorByTypeConstructor(mapOf(this.typeConstructor(context) to this), context)
return substitutor.substituteOrNull(unsubstitutedType)
return valueParameter.returnTypeRef.coneType
}
@@ -497,6 +497,11 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
?: session.builtinTypes.nullableAnyType.type
}
override fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): KotlinTypeMarker? {
require(this is ConeKotlinType)
return unsubstitutedUnderlyingTypeForInlineClass(session)
}
override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? {
require(this is ConeKotlinType)
return substitutedUnderlyingTypeForInlineClass(session, this@ConeTypeContext)
@@ -468,7 +468,7 @@ class ExpressionCodegen(
if (isSuspensionPoint != SuspensionPointKind.NEVER) {
addSuspendMarker(mv, isStartNotEnd = false, isSuspensionPoint == SuspensionPointKind.NOT_INLINE)
if (unboxedInlineClassIrType != null) {
generateResumePathUnboxing(mv, unboxedInlineClassIrType.toIrBasedKotlinType())
generateResumePathUnboxing(mv, unboxedInlineClassIrType, typeMapper)
}
addInlineMarker(mv, isStartNotEnd = false)
}
@@ -484,7 +484,7 @@ class ExpressionCodegen(
mv.checkcast(unboxedInlineClassIrType.asmType)
}
if (irFunction.isInvokeSuspendOfContinuation()) {
StackValue.boxInlineClass(unboxedInlineClassIrType.toIrBasedKotlinType(), mv)
StackValue.boxInlineClass(unboxedInlineClassIrType, mv, typeMapper)
}
}
@@ -637,7 +637,7 @@ class ExpressionCodegen(
if (!irFunction.isInlineCallableReference) return
if (irFunction.extensionReceiverParameter?.symbol == arg.symbol) return
if (arg.type.isNullable() && arg.type.makeNotNull().unboxInlineClass().isNullable()) return
StackValue.unboxInlineClass(OBJECT_TYPE, arg.type.erasedUpperBound.defaultType.toIrBasedKotlinType(), mv)
StackValue.unboxInlineClass(OBJECT_TYPE, arg.type.erasedUpperBound.defaultType, mv, typeMapper)
}
// We do not mangle functions if Result is the only parameter of the function,
@@ -664,7 +664,7 @@ class ExpressionCodegen(
// Result parameter of SAM-wrapper to Java SAM is already unboxed in visitGetValue, do not unbox it anymore
if (irFunction.parentAsClass.superTypes.any { it.getClass()?.isFromJava() == true }) return
StackValue.unboxInlineClass(OBJECT_TYPE, arg.type.erasedUpperBound.defaultType.toIrBasedKotlinType(), mv)
StackValue.unboxInlineClass(OBJECT_TYPE, arg.type.erasedUpperBound.defaultType, mv, typeMapper)
}
private fun IrClass.isSamAdapter(): Boolean = this.superTypes.any { it.getClass()?.isFun == true }
@@ -920,7 +920,7 @@ class ExpressionCodegen(
expression.value.accept(this, data).materializeAt(returnType, returnIrType)
// In case of non-local return from suspend lambda 'materializeAt' does not box return value, box it manually.
if (isNonLocalReturn && owner.isInvokeSuspendOfLambda() && expression.value.type.isKotlinResult()) {
StackValue.boxInlineClass(expression.value.type.toIrBasedKotlinType(), mv)
StackValue.boxInlineClass(expression.value.type, mv, typeMapper)
}
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data, null)
expression.markLineNumber(startOffset = true)
@@ -40,7 +40,7 @@ import org.jetbrains.kotlin.ir.types.isKClass as isKClassImpl
import org.jetbrains.kotlin.ir.util.isSuspendFunction as isSuspendFunctionImpl
class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBase(), TypeMappingContext<JvmSignatureWriter> {
internal val typeSystem = IrTypeSystemContextImpl(context.irBuiltIns)
override val typeSystem: IrTypeSystemContext = IrTypeSystemContextImpl(context.irBuiltIns)
override val typeContext: TypeSystemCommonBackendContextForTypeMapping = IrTypeCheckerContextForTypeMapping(typeSystem, context)
override fun mapClass(classifier: ClassifierDescriptor): Type =
@@ -53,6 +53,9 @@ class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBas
error("Unknown descriptor: $classifier")
}
override fun mapTypeCommon(type: KotlinTypeMarker, mode: TypeMappingMode): Type =
mapType(type as IrType, mode)
private fun computeClassInternalName(irClass: IrClass): StringBuilder {
context.getLocalClassType(irClass)?.internalName?.let {
return StringBuilder(it)
@@ -12,15 +12,11 @@ import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.isTypeParameter
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.substitute
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import org.jetbrains.kotlin.types.model.typeConstructor
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -50,12 +46,12 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
when {
isFromTypeUnboxed && !isToTypeUnboxed -> {
StackValue.boxInlineClass(erasedSourceType.toIrBasedKotlinType(), mv)
StackValue.boxInlineClass(erasedSourceType, mv, typeMapper)
return
}
!isFromTypeUnboxed && isToTypeUnboxed -> {
StackValue.unboxInlineClass(type, erasedTargetType.toIrBasedKotlinType(), mv)
StackValue.unboxInlineClass(type, erasedTargetType, mv, typeMapper)
return
}
}
@@ -64,7 +60,6 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
if (type != target || (castForReified && irType.anyTypeArgument { it.isReified })) {
StackValue.coerce(type, target, mv, type == target)
}
}
abstract fun discard()
@@ -431,20 +431,22 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
irClass.kind != ClassKind.INTERFACE && irClass.kind != ClassKind.ANNOTATION_CLASS
} ?: owner.superTypes.first()
override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? {
override fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): KotlinTypeMarker? {
// Code in inlineClassesUtils.kt loads the property with the same name from the scope of the substituted type and takes its type.
// This code below should have the same effect.
val irClass = (this as? IrType)?.classOrNull?.owner?.takeIf { it.isInline } ?: return null
val inlineClassParameter = irClass.primaryConstructor?.valueParameters?.singleOrNull()
return inlineClassParameter?.let { parameter ->
val irClass = (this as? IrType)?.classOrNull?.owner?.takeIf { it.isInline }
return irClass?.primaryConstructor?.valueParameters?.singleOrNull()?.type
}
override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? =
getUnsubstitutedUnderlyingType()?.let { type ->
// Taking only the type parameters of the class (and not its outer classes) is OK since inner classes are always top level
IrTypeSubstitutor(
irClass.typeParameters.map { it.symbol },
(this as IrType).getClass()!!.typeParameters.map { it.symbol },
(this as? IrSimpleType)?.arguments.orEmpty(),
irBuiltIns
).substitute(parameter.type)
).substitute(type as IrType)
}
}
override fun TypeConstructorMarker.getPrimitiveType(): PrimitiveType? {
if (this !is IrClassSymbol) return null
@@ -34,6 +34,7 @@ interface TypeSystemCommonBackendContext : TypeSystemContext {
fun TypeConstructorMarker.isInlineClass(): Boolean
fun TypeConstructorMarker.isInnerClass(): Boolean
fun TypeParameterMarker.getRepresentativeUpperBound(): KotlinTypeMarker
fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): KotlinTypeMarker?
fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker?
fun KotlinTypeMarker.makeNullable(): KotlinTypeMarker =
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.resolve.descriptorUtil.*
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.substitutedUnderlyingType
import org.jetbrains.kotlin.resolve.unsubstitutedUnderlyingType
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
@@ -645,6 +646,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
return representativeUpperBound
}
override fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): KotlinTypeMarker? {
require(this is KotlinType, this::errorMessage)
return unsubstitutedUnderlyingType()
}
override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? {
require(this is KotlinType, this::errorMessage)
return substitutedUnderlyingType()