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 =
|
private val resultClassStub: IrClassSymbol =
|
||||||
createClass(StandardNames.RESULT_FQ_NAME, classIsInline = true) { klass ->
|
createClass(StandardNames.RESULT_FQ_NAME, classIsInline = true) { klass ->
|
||||||
klass.addTypeParameter("T", irBuiltIns.anyNType, Variance.OUT_VARIANCE)
|
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)
|
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.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.eraseTypeParameters
|
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.backend.jvm.lower.inlineclasses.*
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.kotlin.codegen.StackValue
|
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.declarations.IrTypeParameter
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.*
|
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.isTypeParameter
|
||||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
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) {
|
open fun materializeAt(target: Type, irTarget: IrType, castForReified: Boolean) {
|
||||||
val erasedSourceType = irType.eraseTypeParameters()
|
val erasedSourceType = irType.eraseTypeParameters()
|
||||||
val erasedTargetType = irTarget.eraseTypeParameters()
|
val erasedTargetType = irTarget.eraseTypeParameters()
|
||||||
val isFromTypeInlineClass = erasedSourceType.classOrNull!!.owner.isInline
|
val fromTypeRepresentation = erasedSourceType.getClass()!!.inlineClassRepresentation
|
||||||
val isToTypeInlineClass = erasedTargetType.classOrNull!!.owner.isInline
|
val toTypeRepresentation = erasedTargetType.getClass()!!.inlineClassRepresentation
|
||||||
|
|
||||||
// Boxing and unboxing kotlin.Result leads to CCE in generated code
|
// Boxing and unboxing kotlin.Result leads to CCE in generated code
|
||||||
val doNotCoerceKotlinResultInContinuation =
|
val doNotCoerceKotlinResultInContinuation =
|
||||||
@@ -42,9 +40,9 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
|
|||||||
&& (irType.isKotlinResult() || irTarget.isKotlinResult())
|
&& (irType.isKotlinResult() || irTarget.isKotlinResult())
|
||||||
|
|
||||||
// Coerce inline classes
|
// Coerce inline classes
|
||||||
if ((isFromTypeInlineClass || isToTypeInlineClass) && !doNotCoerceKotlinResultInContinuation) {
|
if ((fromTypeRepresentation != null || toTypeRepresentation != null) && !doNotCoerceKotlinResultInContinuation) {
|
||||||
val isFromTypeUnboxed = isFromTypeInlineClass && typeMapper.mapType(erasedSourceType.unboxed) == type
|
val isFromTypeUnboxed = fromTypeRepresentation?.underlyingType?.let(typeMapper::mapType) == type
|
||||||
val isToTypeUnboxed = isToTypeInlineClass && typeMapper.mapType(erasedTargetType.unboxed) == target
|
val isToTypeUnboxed = toTypeRepresentation?.underlyingType?.let(typeMapper::mapType) == target
|
||||||
|
|
||||||
when {
|
when {
|
||||||
isFromTypeUnboxed && !isToTypeUnboxed -> {
|
isFromTypeUnboxed && !isToTypeUnboxed -> {
|
||||||
@@ -181,9 +179,6 @@ fun PromisedValue.materializeAtBoxed(irTarget: IrType) {
|
|||||||
materializeAt(typeMapper.boxType(irTarget), irTarget)
|
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.
|
// A Non-materialized value of Unit type that is only materialized through coercion.
|
||||||
val ExpressionCodegen.unitValue: PromisedValue
|
val ExpressionCodegen.unitValue: PromisedValue
|
||||||
get() = MaterialValue(this, Type.VOID_TYPE, context.irBuiltIns.unitType)
|
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>? {
|
private fun transformFunctionFlat(function: IrFunction): List<IrDeclaration>? {
|
||||||
if (function.isPrimaryInlineClassConstructor)
|
if (function is IrConstructor && function.isPrimary && function.constructedClass.isInline)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
val replacement = context.inlineClassReplacements.getReplacementFunction(function)
|
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.erasedUpperBound
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
|
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.builtins.StandardNames
|
||||||
import org.jetbrains.kotlin.codegen.state.InfoForMangling
|
import org.jetbrains.kotlin.codegen.state.InfoForMangling
|
||||||
import org.jetbrains.kotlin.codegen.state.collectFunctionSignatureForManglingSuffix
|
import org.jetbrains.kotlin.codegen.state.collectFunctionSignatureForManglingSuffix
|
||||||
@@ -40,10 +39,10 @@ object InlineClassAbi {
|
|||||||
*/
|
*/
|
||||||
internal fun unboxType(type: IrType): IrType? {
|
internal fun unboxType(type: IrType): IrType? {
|
||||||
val klass = type.classOrNull?.owner ?: return null
|
val klass = type.classOrNull?.owner ?: return null
|
||||||
if (!klass.isInline) return null
|
val representation = klass.inlineClassRepresentation ?: return null
|
||||||
|
|
||||||
// TODO: Apply type substitutions
|
// TODO: Apply type substitutions
|
||||||
val underlyingType = getUnderlyingType(klass).unboxInlineClass()
|
val underlyingType = representation.underlyingType.unboxInlineClass()
|
||||||
if (!type.isNullable())
|
if (!type.isNullable())
|
||||||
return underlyingType
|
return underlyingType
|
||||||
if (underlyingType.isNullable() || underlyingType.isPrimitiveType())
|
if (underlyingType.isNullable() || underlyingType.isPrimitiveType())
|
||||||
@@ -51,16 +50,6 @@ object InlineClassAbi {
|
|||||||
return underlyingType.makeNullable()
|
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
|
* Returns a mangled name for a function taking inline class arguments
|
||||||
* to avoid clashes between overloaded methods.
|
* to avoid clashes between overloaded methods.
|
||||||
@@ -157,20 +146,9 @@ internal val IrFunction.hasMangledParameters: Boolean
|
|||||||
internal val IrFunction.hasMangledReturnType: Boolean
|
internal val IrFunction.hasMangledReturnType: Boolean
|
||||||
get() = returnType.isInlineClassType() && parentClassOrNull?.isFileClass != true
|
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
|
internal val IrClass.inlineClassFieldName: Name
|
||||||
get() = singlePrimaryConstructorParameter.name
|
get() = (inlineClassRepresentation ?: error("Not an inline class: ${render()}")).underlyingPropertyName
|
||||||
|
|
||||||
val IrFunction.isInlineClassFieldGetter: Boolean
|
val IrFunction.isInlineClassFieldGetter: Boolean
|
||||||
get() = (parent as? IrClass)?.isInline == true && this is IrSimpleFunction && extensionReceiverParameter == null &&
|
get() = (parent as? IrClass)?.isInline == true && this is IrSimpleFunction && extensionReceiverParameter == null &&
|
||||||
correspondingPropertySymbol?.let { it.owner.getter == this && it.owner.name == parentAsClass.inlineClassFieldName } == true
|
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)
|
copyTypeParametersFrom(irClass)
|
||||||
addValueParameter {
|
addValueParameter {
|
||||||
name = InlineClassDescriptorResolver.BOXING_VALUE_PARAMETER_NAME
|
name = InlineClassDescriptorResolver.BOXING_VALUE_PARAMETER_NAME
|
||||||
type = InlineClassAbi.getUnderlyingType(irClass)
|
type = irClass.inlineClassRepresentation!!.underlyingType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ class MemoizedInlineClassReplacements(
|
|||||||
irFactory.buildFun {
|
irFactory.buildFun {
|
||||||
name = Name.identifier(KotlinTypeMapper.UNBOX_JVM_METHOD_NAME)
|
name = Name.identifier(KotlinTypeMapper.UNBOX_JVM_METHOD_NAME)
|
||||||
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_INLINE_CLASS_MEMBER
|
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_INLINE_CLASS_MEMBER
|
||||||
returnType = InlineClassAbi.getUnderlyingType(irClass)
|
returnType = irClass.inlineClassRepresentation!!.underlyingType
|
||||||
}.apply {
|
}.apply {
|
||||||
parent = irClass
|
parent = irClass
|
||||||
createDispatchReceiverParameter()
|
createDispatchReceiverParameter()
|
||||||
|
|||||||
@@ -615,7 +615,8 @@ open class IrBasedClassDescriptor(owner: IrClass) : ClassDescriptor, IrBasedDecl
|
|||||||
TODO("not implemented")
|
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
|
override fun getOriginal() = this
|
||||||
|
|
||||||
|
|||||||
@@ -435,12 +435,8 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
|
|||||||
irClass.kind != ClassKind.INTERFACE && irClass.kind != ClassKind.ANNOTATION_CLASS
|
irClass.kind != ClassKind.INTERFACE && irClass.kind != ClassKind.ANNOTATION_CLASS
|
||||||
} ?: owner.superTypes.first()
|
} ?: owner.superTypes.first()
|
||||||
|
|
||||||
override fun KotlinTypeMarker.getUnsubstitutedUnderlyingType(): 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 as IrType).classOrNull?.owner?.inlineClassRepresentation?.underlyingType
|
||||||
// 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.getSubstitutedUnderlyingType(): KotlinTypeMarker? =
|
override fun KotlinTypeMarker.getSubstitutedUnderlyingType(): KotlinTypeMarker? =
|
||||||
getUnsubstitutedUnderlyingType()?.let { type ->
|
getUnsubstitutedUnderlyingType()?.let { type ->
|
||||||
|
|||||||
@@ -7,37 +7,24 @@ package org.jetbrains.kotlin.resolve
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
|
||||||
import org.jetbrains.kotlin.types.Variance
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
val JVM_INLINE_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmInline")
|
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: DeserializedClassDescriptor in reflection do not have @JvmInline annotation, that we
|
||||||
// FIXME: would like to check as well.
|
// 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? {
|
fun KotlinType.unsubstitutedUnderlyingType(): KotlinType? =
|
||||||
return constructor.declarationDescriptor.safeAs<ClassDescriptor>()?.underlyingRepresentation()
|
constructor.declarationDescriptor.safeAs<ClassDescriptor>()?.inlineClassRepresentation?.underlyingType
|
||||||
}
|
|
||||||
|
|
||||||
fun KotlinType.unsubstitutedUnderlyingType(): KotlinType? = unsubstitutedUnderlyingParameter()?.type
|
|
||||||
|
|
||||||
fun KotlinType.isInlineClassType(): Boolean = constructor.declarationDescriptor?.isInlineClass() ?: false
|
fun KotlinType.isInlineClassType(): Boolean = constructor.declarationDescriptor?.isInlineClass() ?: false
|
||||||
|
|
||||||
fun KotlinType.substitutedUnderlyingType(): KotlinType? {
|
fun KotlinType.substitutedUnderlyingType(): KotlinType? =
|
||||||
val parameter = unsubstitutedUnderlyingParameter() ?: return null
|
unsubstitutedUnderlyingType()?.let { TypeSubstitutor.create(this).substitute(it, Variance.INVARIANT) }
|
||||||
return TypeSubstitutor.create(this).substitute(parameter.type, Variance.INVARIANT)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun KotlinType.isRecursiveInlineClassType() =
|
fun KotlinType.isRecursiveInlineClassType(): Boolean =
|
||||||
isRecursiveInlineClassTypeInner(hashSetOf())
|
isRecursiveInlineClassTypeInner(hashSetOf())
|
||||||
|
|
||||||
private fun KotlinType.isRecursiveInlineClassTypeInner(visited: HashSet<ClassifierDescriptor>): Boolean {
|
private fun KotlinType.isRecursiveInlineClassTypeInner(visited: HashSet<ClassifierDescriptor>): Boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user