JVM IR: use inlineClassRepresentation in more utilities
Remove any logic related to finding the single parameter of the primary constructor, and use inlineClassRepresentaton from IrClass or ClassDescriptor instead.
This commit is contained in:
@@ -247,9 +247,6 @@ class JvmSymbols(
|
||||
private val resultClassStub: IrClassSymbol =
|
||||
createClass(StandardNames.RESULT_FQ_NAME, classIsInline = true) { klass ->
|
||||
klass.addTypeParameter("T", irBuiltIns.anyNType, Variance.OUT_VARIANCE)
|
||||
klass.addConstructor { isPrimary = true }.apply {
|
||||
addValueParameter("value", irBuiltIns.anyNType)
|
||||
}
|
||||
klass.inlineClassRepresentation = InlineClassRepresentation(Name.identifier("value"), irBuiltIns.anyNType as IrSimpleType)
|
||||
}
|
||||
|
||||
|
||||
+5
-10
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.jvm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.eraseTypeParameters
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.*
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
@@ -15,7 +14,6 @@ import org.jetbrains.kotlin.codegen.inline.v
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.isTypeParameter
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
@@ -31,8 +29,8 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
|
||||
open fun materializeAt(target: Type, irTarget: IrType, castForReified: Boolean) {
|
||||
val erasedSourceType = irType.eraseTypeParameters()
|
||||
val erasedTargetType = irTarget.eraseTypeParameters()
|
||||
val isFromTypeInlineClass = erasedSourceType.classOrNull!!.owner.isInline
|
||||
val isToTypeInlineClass = erasedTargetType.classOrNull!!.owner.isInline
|
||||
val fromTypeRepresentation = erasedSourceType.getClass()!!.inlineClassRepresentation
|
||||
val toTypeRepresentation = erasedTargetType.getClass()!!.inlineClassRepresentation
|
||||
|
||||
// Boxing and unboxing kotlin.Result leads to CCE in generated code
|
||||
val doNotCoerceKotlinResultInContinuation =
|
||||
@@ -42,9 +40,9 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
|
||||
&& (irType.isKotlinResult() || irTarget.isKotlinResult())
|
||||
|
||||
// Coerce inline classes
|
||||
if ((isFromTypeInlineClass || isToTypeInlineClass) && !doNotCoerceKotlinResultInContinuation) {
|
||||
val isFromTypeUnboxed = isFromTypeInlineClass && typeMapper.mapType(erasedSourceType.unboxed) == type
|
||||
val isToTypeUnboxed = isToTypeInlineClass && typeMapper.mapType(erasedTargetType.unboxed) == target
|
||||
if ((fromTypeRepresentation != null || toTypeRepresentation != null) && !doNotCoerceKotlinResultInContinuation) {
|
||||
val isFromTypeUnboxed = fromTypeRepresentation?.underlyingType?.let(typeMapper::mapType) == type
|
||||
val isToTypeUnboxed = toTypeRepresentation?.underlyingType?.let(typeMapper::mapType) == target
|
||||
|
||||
when {
|
||||
isFromTypeUnboxed && !isToTypeUnboxed -> {
|
||||
@@ -181,9 +179,6 @@ fun PromisedValue.materializeAtBoxed(irTarget: IrType) {
|
||||
materializeAt(typeMapper.boxType(irTarget), irTarget)
|
||||
}
|
||||
|
||||
val IrType.unboxed: IrType
|
||||
get() = InlineClassAbi.getUnderlyingType(erasedUpperBound)
|
||||
|
||||
// A Non-materialized value of Unit type that is only materialized through coercion.
|
||||
val ExpressionCodegen.unitValue: PromisedValue
|
||||
get() = MaterialValue(this, Type.VOID_TYPE, context.irBuiltIns.unitType)
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F
|
||||
}
|
||||
|
||||
private fun transformFunctionFlat(function: IrFunction): List<IrDeclaration>? {
|
||||
if (function.isPrimaryInlineClassConstructor)
|
||||
if (function is IrConstructor && function.isPrimary && function.constructedClass.isInline)
|
||||
return null
|
||||
|
||||
val replacement = context.inlineClassReplacements.getReplacementFunction(function)
|
||||
|
||||
+3
-25
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.backend.jvm.lower.inlineclasses
|
||||
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.STUB_FOR_INLINING
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.codegen.state.InfoForMangling
|
||||
import org.jetbrains.kotlin.codegen.state.collectFunctionSignatureForManglingSuffix
|
||||
@@ -40,10 +39,10 @@ object InlineClassAbi {
|
||||
*/
|
||||
internal fun unboxType(type: IrType): IrType? {
|
||||
val klass = type.classOrNull?.owner ?: return null
|
||||
if (!klass.isInline) return null
|
||||
val representation = klass.inlineClassRepresentation ?: return null
|
||||
|
||||
// TODO: Apply type substitutions
|
||||
val underlyingType = getUnderlyingType(klass).unboxInlineClass()
|
||||
val underlyingType = representation.underlyingType.unboxInlineClass()
|
||||
if (!type.isNullable())
|
||||
return underlyingType
|
||||
if (underlyingType.isNullable() || underlyingType.isPrimitiveType())
|
||||
@@ -51,16 +50,6 @@ object InlineClassAbi {
|
||||
return underlyingType.makeNullable()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying type of an inline class based on the single argument to its
|
||||
* primary constructor. This is what the current jvm backend does.
|
||||
*
|
||||
* Looking for a backing field does not work for unsigned types, which don't
|
||||
* contain a field.
|
||||
*/
|
||||
fun getUnderlyingType(irClass: IrClass): IrType =
|
||||
irClass.singlePrimaryConstructorParameter.type
|
||||
|
||||
/**
|
||||
* Returns a mangled name for a function taking inline class arguments
|
||||
* to avoid clashes between overloaded methods.
|
||||
@@ -157,20 +146,9 @@ internal val IrFunction.hasMangledParameters: Boolean
|
||||
internal val IrFunction.hasMangledReturnType: Boolean
|
||||
get() = returnType.isInlineClassType() && parentClassOrNull?.isFileClass != true
|
||||
|
||||
private val IrClass.singlePrimaryConstructorParameter: IrValueParameter
|
||||
get() {
|
||||
require(isInline) { "Not an inline class: ${render()} "}
|
||||
val primaryConstructor = primaryConstructor ?: error("Inline class has no primary constructor: ${render()}")
|
||||
return primaryConstructor.valueParameters.singleOrNull()
|
||||
?: error("Inline class primary constructor should have one parameter: ${primaryConstructor.render()}")
|
||||
}
|
||||
|
||||
internal val IrClass.inlineClassFieldName: Name
|
||||
get() = singlePrimaryConstructorParameter.name
|
||||
get() = (inlineClassRepresentation ?: error("Not an inline class: ${render()}")).underlyingPropertyName
|
||||
|
||||
val IrFunction.isInlineClassFieldGetter: Boolean
|
||||
get() = (parent as? IrClass)?.isInline == true && this is IrSimpleFunction && extensionReceiverParameter == null &&
|
||||
correspondingPropertySymbol?.let { it.owner.getter == this && it.owner.name == parentAsClass.inlineClassFieldName } == true
|
||||
|
||||
val IrFunction.isPrimaryInlineClassConstructor: Boolean
|
||||
get() = this is IrConstructor && isPrimary && constructedClass.isInline
|
||||
|
||||
+2
-2
@@ -131,7 +131,7 @@ class MemoizedInlineClassReplacements(
|
||||
copyTypeParametersFrom(irClass)
|
||||
addValueParameter {
|
||||
name = InlineClassDescriptorResolver.BOXING_VALUE_PARAMETER_NAME
|
||||
type = InlineClassAbi.getUnderlyingType(irClass)
|
||||
type = irClass.inlineClassRepresentation!!.underlyingType
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ class MemoizedInlineClassReplacements(
|
||||
irFactory.buildFun {
|
||||
name = Name.identifier(KotlinTypeMapper.UNBOX_JVM_METHOD_NAME)
|
||||
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_INLINE_CLASS_MEMBER
|
||||
returnType = InlineClassAbi.getUnderlyingType(irClass)
|
||||
returnType = irClass.inlineClassRepresentation!!.underlyingType
|
||||
}.apply {
|
||||
parent = irClass
|
||||
createDispatchReceiverParameter()
|
||||
|
||||
@@ -615,7 +615,8 @@ open class IrBasedClassDescriptor(owner: IrClass) : ClassDescriptor, IrBasedDecl
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? = TODO("not implemented")
|
||||
override fun getInlineClassRepresentation(): InlineClassRepresentation<SimpleType>? =
|
||||
owner.inlineClassRepresentation?.mapUnderlyingType { it.toIrBasedKotlinType() as SimpleType }
|
||||
|
||||
override fun getOriginal() = this
|
||||
|
||||
|
||||
@@ -435,12 +435,8 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
|
||||
irClass.kind != ClassKind.INTERFACE && irClass.kind != ClassKind.ANNOTATION_CLASS
|
||||
} ?: owner.superTypes.first()
|
||||
|
||||
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 irClass?.primaryConstructor?.valueParameters?.singleOrNull()?.type
|
||||
}
|
||||
override fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): KotlinTypeMarker? =
|
||||
(this as IrType).classOrNull?.owner?.inlineClassRepresentation?.underlyingType
|
||||
|
||||
override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? =
|
||||
getUnsubstitutedUnderlyingType()?.let { type ->
|
||||
|
||||
@@ -7,37 +7,24 @@ package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
val JVM_INLINE_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmInline")
|
||||
|
||||
private fun ClassDescriptor.underlyingRepresentation(): ValueParameterDescriptor? {
|
||||
if (!isInlineClass()) return null
|
||||
return unsubstitutedPrimaryConstructor?.valueParameters?.singleOrNull()
|
||||
}
|
||||
|
||||
// FIXME: DeserializedClassDescriptor in reflection do not have @JvmInline annotation, that we
|
||||
// FIXME: would like to check as well.
|
||||
fun DeclarationDescriptor.isInlineClass() = this is ClassDescriptor && (isInline || isValue)
|
||||
fun DeclarationDescriptor.isInlineClass(): Boolean = this is ClassDescriptor && (isInline || isValue)
|
||||
|
||||
private fun KotlinType.unsubstitutedUnderlyingParameter(): ValueParameterDescriptor? {
|
||||
return constructor.declarationDescriptor.safeAs<ClassDescriptor>()?.underlyingRepresentation()
|
||||
}
|
||||
|
||||
fun KotlinType.unsubstitutedUnderlyingType(): KotlinType? = unsubstitutedUnderlyingParameter()?.type
|
||||
fun KotlinType.unsubstitutedUnderlyingType(): KotlinType? =
|
||||
constructor.declarationDescriptor.safeAs<ClassDescriptor>()?.inlineClassRepresentation?.underlyingType
|
||||
|
||||
fun KotlinType.isInlineClassType(): Boolean = constructor.declarationDescriptor?.isInlineClass() ?: false
|
||||
|
||||
fun KotlinType.substitutedUnderlyingType(): KotlinType? {
|
||||
val parameter = unsubstitutedUnderlyingParameter() ?: return null
|
||||
return TypeSubstitutor.create(this).substitute(parameter.type, Variance.INVARIANT)
|
||||
}
|
||||
fun KotlinType.substitutedUnderlyingType(): KotlinType? =
|
||||
unsubstitutedUnderlyingType()?.let { TypeSubstitutor.create(this).substitute(it, Variance.INVARIANT) }
|
||||
|
||||
fun KotlinType.isRecursiveInlineClassType() =
|
||||
fun KotlinType.isRecursiveInlineClassType(): Boolean =
|
||||
isRecursiveInlineClassTypeInner(hashSetOf())
|
||||
|
||||
private fun KotlinType.isRecursiveInlineClassTypeInner(visited: HashSet<ClassifierDescriptor>): Boolean {
|
||||
|
||||
Reference in New Issue
Block a user