From b59ac5d8f651ef2084705aa0f2cf4b63720f3cdc Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 31 Mar 2021 17:03:38 +0200 Subject: [PATCH] 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. --- .../kotlin/codegen/CallableMethod.kt | 3 +- .../FunctionsFromAnyGeneratorImpl.java | 5 +- .../jetbrains/kotlin/codegen/StackValue.java | 42 +++++++++----- .../codegen/coroutines/CoroutineCodegen.kt | 7 +-- .../codegen/inline/inlineCodegenUtils.kt | 14 +++-- .../kotlin/codegen/state/KotlinTypeMapper.kt | 58 +++++-------------- .../codegen/state/KotlinTypeMapperBase.kt | 7 +++ .../state/StaticTypeMapperForOldBackend.kt | 54 +++++++++++++++++ .../fir/declarations/InlineClassesUtils.kt | 18 ++++-- .../kotlin/fir/types/ConeTypeContext.kt | 5 ++ .../backend/jvm/codegen/ExpressionCodegen.kt | 10 ++-- .../backend/jvm/codegen/IrTypeMapper.kt | 5 +- .../backend/jvm/codegen/PromisedValue.kt | 9 +-- .../kotlin/ir/types/IrTypeSystemContext.kt | 16 ++--- .../types/TypeSystemCommonBackendContext.kt | 1 + .../types/checker/ClassicTypeSystemContext.kt | 6 ++ 16 files changed, 162 insertions(+), 98 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/state/StaticTypeMapperForOldBackend.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt index bad19c172b0..751dd1be912 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt @@ -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, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java index 0d7dc837228..dd86b2fb30e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionsFromAnyGeneratorImpl.java @@ -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; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 4a76cc9bce7..aa7b669fbcc 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -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) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index f2439415d67..d7d0f1fe0bb 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -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 = - (listOfNotNull(extensionReceiverParameter?.type)) + valueParameters.map { it.type } \ No newline at end of file + (listOfNotNull(extensionReceiverParameter?.type)) + valueParameters.map { it.type } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index 1e9eca5483e..18d9eecdba0 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -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. diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt index 3d94bc36658..67118204301 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.kt @@ -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 { override fun commonSupertype(types: Collection): 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 { - override fun commonSupertype(types: Collection): 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 = - 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})." diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapperBase.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapperBase.kt index 63e778f2957..7f252efcfe5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapperBase.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapperBase.kt @@ -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) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/StaticTypeMapperForOldBackend.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/StaticTypeMapperForOldBackend.kt new file mode 100644 index 00000000000..d134a760186 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/StaticTypeMapperForOldBackend.kt @@ -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 { + override fun commonSupertype(types: Collection): 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) + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/declarations/InlineClassesUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/declarations/InlineClassesUtils.kt index a461821e11a..e39b8d6ca9a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/declarations/InlineClassesUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/declarations/InlineClassesUtils.kt @@ -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 } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index 470c36c966a..45f9bc4cf66 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -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) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 6bc7059c98f..0ced5396255 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -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) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt index 034ca808618..3b88f871b24 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrTypeMapper.kt @@ -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 { - 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) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt index a04c91af2ce..24735061dde 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt @@ -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() diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index 948adec804a..7e378bbfba6 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -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 diff --git a/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt b/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt index 1fd2917e485..75715abd8b3 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt @@ -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 = diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index e815d9babbe..4575fee58ee 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -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()