diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/declarations/declarationBuilders.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/declarations/declarationBuilders.kt index d36ea6dde48..405c6a449cb 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/declarations/declarationBuilders.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/declarations/declarationBuilders.kt @@ -127,7 +127,7 @@ fun IrFunctionBuilder.buildFun(originalDescriptor: FunctionDescriptor? = null): } } -fun IrFunctionBuilder.buildConstructor(): IrConstructor { +fun IrFunctionBuilder.buildConstructor(): IrConstructorImpl { val wrappedDescriptor = WrappedClassConstructorDescriptor() return IrConstructorImpl( startOffset, endOffset, origin, @@ -179,13 +179,13 @@ fun IrDeclarationContainer.addFunction( } } -inline fun buildConstructor(builder: IrFunctionBuilder.() -> Unit): IrConstructor = +inline fun buildConstructor(builder: IrFunctionBuilder.() -> Unit): IrConstructorImpl = IrFunctionBuilder().run { builder() buildConstructor() } -inline fun IrClass.addConstructor(builder: IrFunctionBuilder.() -> Unit = {}): IrConstructor = +inline fun IrClass.addConstructor(builder: IrFunctionBuilder.() -> Unit = {}): IrConstructorImpl = buildConstructor { builder() returnType = defaultType diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt index 9c72f2e6c63..d175a2502cf 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/irCodegenUtils.kt @@ -188,18 +188,6 @@ private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?): return Opcodes.ACC_PRIVATE } -// if (kind !== OwnerKind.ERASED_INLINE_CLASS && -// memberDescriptor is ConstructorDescriptor && -// memberDescriptor !is AccessorForConstructorDescriptor && -// shouldHideConstructorDueToInlineClassTypeValueParameters(memberDescriptor) -// ) { - if (kind !== OwnerKind.ERASED_INLINE_CLASS && - this is IrConstructor && - shouldHideDueToInlineClassTypeValueParameters() - ) { - return Opcodes.ACC_PRIVATE - } - // if (memberDescriptor.isEffectivelyInlineOnly()) { if (isEffectivelyInlineOnly()) { return Opcodes.ACC_PRIVATE @@ -286,30 +274,6 @@ private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?): return null } -/* From inlineClassManglingRules.kt */ -fun IrConstructor.shouldHideDueToInlineClassTypeValueParameters() = - !Visibilities.isPrivate(visibility) && - !parentAsClass.isInline && - parentAsClass.modality !== Modality.SEALED && - valueParameters.any { it.type.requiresFunctionNameMangling() } - -fun IrType.requiresFunctionNameMangling(): Boolean = - isInlineClassThatRequiresMangling() || isTypeParameterWithUpperBoundThatRequiresMangling() - -fun IrType.isInlineClassThatRequiresMangling() = - safeAs()?.classifier?.owner?.safeAs()?.let { - it.isInline && !it.isDontMangleClass() - } ?: false - -fun IrClass.isDontMangleClass() = - fqNameWhenAvailable != DescriptorUtils.RESULT_FQ_NAME - -fun IrType.isTypeParameterWithUpperBoundThatRequiresMangling() = - safeAs()?.classifier?.owner.safeAs()?.let { param -> - param.superTypes.any { it.requiresFunctionNameMangling() } - } ?: false - - /* Borrowed from InlineUtil. */ private tailrec fun isInlineOrContainedInInline(declaration: IrDeclaration?): Boolean = when { declaration === null -> false diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt index 3dcc7dfae9d..91fd0a48516 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt @@ -9,12 +9,15 @@ import org.jetbrains.kotlin.backend.common.lower.IrLoweringContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmSymbols import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface +import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.hasMangledParameters import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope import org.jetbrains.kotlin.ir.builders.Scope import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns +import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol @@ -96,6 +99,9 @@ fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = else irBuiltIns.primitiveArrayElementTypes.getValue(this.classOrNull!!) +val IrConstructor.shouldBeHidden: Boolean + get() = !Visibilities.isPrivate(visibility) && !constructedClass.isInline && hasMangledParameters + // An IR builder with a reference to the JvmBackendContext class JvmIrBuilder( val backendContext: JvmBackendContext, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt index b52c1f250fd..c82e2c539e3 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/CallableReferenceLowering.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder import org.jetbrains.kotlin.backend.jvm.ir.irArray import org.jetbrains.kotlin.backend.jvm.ir.isInlineParameter +import org.jetbrains.kotlin.backend.jvm.ir.shouldBeHidden import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.IrElement @@ -40,6 +41,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.org.objectweb.asm.Type internal val callableReferencePhase = makeIrFilePhase( ::CallableReferenceLowering, @@ -383,7 +385,17 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) DescriptorUtils.unwrapFakeOverride(irFunctionReference.symbol.descriptor).original ).owner val method = codegenContext.methodSignatureMapper.mapAsmMethod(declaration) - irExprBody(irString(method.name + method.descriptor)) + // HACK: When referencing a constructor taking inline class parameters, we will actually + // end up calling a public bridge method with an additional argument. + // TODO: Don't compute signatures in CallableReferenceLowering + val descriptor = if (declaration is IrConstructor && declaration.shouldBeHidden) { + val marker = + codegenContext.typeMapper.mapType(codegenContext.ir.symbols.defaultConstructorMarker.owner.defaultType) + Type.getMethodDescriptor(method.returnType, *method.argumentTypes, marker) + } else { + method.descriptor + } + irExprBody(irString(method.name + descriptor)) } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt index 56695aac149..090e66936fd 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SyntheticAccessorLowering.kt @@ -11,10 +11,10 @@ import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom import org.jetbrains.kotlin.backend.common.ir.copyValueParametersToStatic import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom import org.jetbrains.kotlin.backend.common.ir.remapTypeParameters -import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.intrinsics.receiverAndArgs +import org.jetbrains.kotlin.backend.jvm.ir.shouldBeHidden import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.symbols.* @@ -32,10 +33,13 @@ import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.isSubtypeOfClass import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid +import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.utils.addToStdlib.safeAs internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass { private val pendingTransformations = mutableListOf>() @@ -43,6 +47,44 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle override fun lower(irFile: IrFile) { inlineLambdaToCallSite.putAll(InlineReferenceLocator.scan(context, irFile).lambdaToCallSite) + + // Unconditionally add bridges for hidden constructors + irFile.acceptChildrenVoid(object: IrElementVisitorVoid { + override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this) + + private fun handleConstructor(declaration: IrConstructor) { + if (!declaration.shouldBeHidden) + return + + declaration.visibility = Visibilities.PRIVATE + + functionMap.computeIfAbsent(declaration.symbol) { + declaration.makeConstructorAccessor().also { accessor -> + // There's a special case in the JVM backend for serializing the metadata of hidden + // constructors - we serialize the descriptor of the original constructor, but the + // signature of the bridge. We implement this special case in the JVM IR backend by + // attaching the metadata directly to the bridge. We also have to move all annotations + // to the bridge method. Parameter annotations are already moved by the copyTo method. + accessor.metadata = declaration.metadata + declaration.safeAs()?.metadata = null + accessor.annotations += declaration.annotations + declaration.annotations.clear() + declaration.valueParameters.forEach { it.annotations.clear() } + }.symbol + } + } + + override fun visitConstructor(declaration: IrConstructor) { + handleConstructor(declaration) + super.visitConstructor(declaration) + } + + override fun visitConstructorCall(expression: IrConstructorCall) { + handleConstructor(expression.symbol.owner) + super.visitConstructorCall(expression) + } + }) + irFile.transformChildrenVoid(this) pendingTransformations.forEach { it() } } @@ -108,7 +150,7 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle classes.lastOrNull { parent is IrClass && it.isSubclassOf(parent) } ?: classes.last() } else parent - private fun IrConstructor.makeConstructorAccessor(): IrConstructor { + private fun IrConstructor.makeConstructorAccessor(): IrConstructorImpl { val source = this return buildConstructor { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt index 8c9e2109db8..8a5df0da386 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/InlineClassAbi.kt @@ -91,15 +91,20 @@ object InlineClassAbi { } } -internal val IrType.requiresMangling: Boolean +private val IrType.requiresMangling: Boolean get() { val irClass = erasedUpperBound return irClass.isInline && irClass.fqNameWhenAvailable != DescriptorUtils.RESULT_FQ_NAME } -internal val IrFunction.fullValueParameterList: List +private val IrFunction.fullValueParameterList: List get() = listOfNotNull(extensionReceiverParameter) + valueParameters +internal val IrFunction.hasMangledParameters: Boolean + get() = dispatchReceiverParameter?.type?.getClass()?.isInline == true || + fullValueParameterList.any { it.type.requiresMangling } || + (this is IrConstructor && constructedClass.isInline) + internal val IrClass.inlineClassFieldName: Name get() = primaryConstructor!!.valueParameters.single().name diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt index ee6de377b2c..9395bf24180 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/inlineclasses/MemoizedInlineClassReplacements.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol -import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.util.constructedClass @@ -57,11 +56,6 @@ class MemoizedInlineClassReplacements { } } - private val IrFunction.hasMangledParameters: Boolean - get() = dispatchReceiverParameter?.type?.getClass()?.isInline == true || - fullValueParameterList.any { it.type.requiresMangling } || - (this is IrConstructor && constructedClass.isInline) - private val IrFunction.hasStaticReplacement: Boolean get() = origin != IrDeclarationOrigin.FAKE_OVERRIDE && (this is IrSimpleFunction || this is IrConstructor && constructedClass.isInline) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrConstructor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrConstructor.kt index 52e57ac9b3d..e2479deeb0d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrConstructor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrConstructor.kt @@ -17,12 +17,15 @@ package org.jetbrains.kotlin.ir.declarations import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol interface IrConstructor : IrFunction, IrSymbolDeclaration { override val descriptor: ClassConstructorDescriptor + override var visibility: Visibility + val isPrimary: Boolean } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionBase.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionBase.kt index 3d29ba187ce..fd53bca1d56 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionBase.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrFunctionBase.kt @@ -31,7 +31,7 @@ abstract class IrFunctionBase( endOffset: Int, origin: IrDeclarationOrigin, override val name: Name, - override val visibility: Visibility, + override var visibility: Visibility, override val isInline: Boolean, override val isExternal: Boolean, returnType: IrType diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt index eb944546693..505a332cccf 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/lazy/IrLazyFunctionBase.kt @@ -23,7 +23,7 @@ abstract class IrLazyFunctionBase( endOffset: Int, origin: IrDeclarationOrigin, override val name: Name, - override val visibility: Visibility, + override var visibility: Visibility, override val isInline: Boolean, override val isExternal: Boolean, stubGenerator: DeclarationStubGenerator, diff --git a/compiler/testData/codegen/box/reflection/call/inlineClasses/constructorWithInlineClassParameters.kt b/compiler/testData/codegen/box/reflection/call/inlineClasses/constructorWithInlineClassParameters.kt index 5c18d5709a8..197439d6e36 100644 --- a/compiler/testData/codegen/box/reflection/call/inlineClasses/constructorWithInlineClassParameters.kt +++ b/compiler/testData/codegen/box/reflection/call/inlineClasses/constructorWithInlineClassParameters.kt @@ -1,4 +1,4 @@ -// IGNORE_BACKEND: JS_IR, JS, NATIVE, JVM_IR +// IGNORE_BACKEND: JS_IR, JS, NATIVE // WITH_REFLECT import kotlin.test.assertEquals diff --git a/compiler/testData/codegen/box/reflection/mapping/constructorWithInlineClassParameters.kt b/compiler/testData/codegen/box/reflection/mapping/constructorWithInlineClassParameters.kt index da2b243f490..2b38cc4e70e 100644 --- a/compiler/testData/codegen/box/reflection/mapping/constructorWithInlineClassParameters.kt +++ b/compiler/testData/codegen/box/reflection/mapping/constructorWithInlineClassParameters.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT import kotlin.reflect.full.primaryConstructor