diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt index 786cbfe303a..aa07ecb8aa5 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/DefaultArgumentStubGenerator.kt @@ -53,10 +53,15 @@ open class DefaultArgumentStubGenerator( } private fun lower(irFunction: IrFunction): List? { - val visibility = defaultArgumentStubVisibility(irFunction) val newIrFunction = - irFunction.generateDefaultsFunction(context, skipInlineMethods, skipExternalMethods, forceSetOverrideSymbols, visibility) - ?: return null + irFunction.generateDefaultsFunction( + context, + skipInlineMethods, + skipExternalMethods, + forceSetOverrideSymbols, + defaultArgumentStubVisibility(irFunction), + useConstructorMarker(irFunction) + ) ?: return null if (newIrFunction.isFakeOverride) { return listOf(irFunction, newIrFunction) } @@ -185,7 +190,8 @@ open class DefaultArgumentStubGenerator( protected open fun IrBlockBodyBuilder.generateSuperCallHandlerCheckIfNeeded( irFunction: IrFunction, - newIrFunction: IrFunction) { + newIrFunction: IrFunction + ) { //NO-OP Stub } @@ -202,6 +208,8 @@ open class DefaultArgumentStubGenerator( protected open fun defaultArgumentStubVisibility(function: IrFunction) = Visibilities.PUBLIC + protected open fun useConstructorMarker(function: IrFunction) = function is IrConstructor + private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" } } @@ -310,15 +318,20 @@ open class DefaultParameterInjector( val startOffset = expression.startOffset val endOffset = expression.endOffset val declaration = expression.symbol.owner - val visibility = defaultArgumentStubVisibility(declaration) // We *have* to find the actual function here since on the JVM, a default stub for a function implemented // in an interface does not leave an abstract method after being moved to DefaultImpls (see InterfaceLowering). // Calling the fake override on an implementation of that interface would then result in a call to a method // that does not actually exist as DefaultImpls is not part of the inheritance hierarchy. val stubFunction = declaration.findBaseFunctionWithDefaultArguments(skipInline, skipExternalMethods) - ?.generateDefaultsFunction(context, skipInline, skipExternalMethods, forceSetOverrideSymbols, visibility) - ?: return null + ?.generateDefaultsFunction( + context, + skipInline, + skipExternalMethods, + forceSetOverrideSymbols, + defaultArgumentStubVisibility(declaration), + useConstructorMarker(declaration) + ) ?: return null log { "$declaration -> $stubFunction" } @@ -367,6 +380,8 @@ open class DefaultParameterInjector( protected open fun defaultArgumentStubVisibility(function: IrFunction) = Visibilities.PUBLIC + protected open fun useConstructorMarker(function: IrFunction) = function is IrConstructor + private fun log(msg: () -> String) = context.log { "DEFAULT-INJECTOR: ${msg()}" } } @@ -416,7 +431,8 @@ private fun IrFunction.generateDefaultsFunction( skipInlineMethods: Boolean, skipExternalMethods: Boolean, forceSetOverrideSymbols: Boolean, - visibility: Visibility + visibility: Visibility, + useConstructorMarker: Boolean ): IrFunction? { if (skipInlineMethods && isInline) return null if (skipExternalMethods && isExternalOrInheritedFromExternal()) return null @@ -425,7 +441,7 @@ private fun IrFunction.generateDefaultsFunction( if (this is IrSimpleFunction) { // If this is an override of a function with default arguments, produce a fake override of a default stub. if (overriddenSymbols.any { it.owner.findBaseFunctionWithDefaultArguments(skipInlineMethods, skipExternalMethods) != null }) - return generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FAKE_OVERRIDE, visibility, isFakeOverride = true).also { + return generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FAKE_OVERRIDE, visibility, true, useConstructorMarker).also { context.mapping.defaultArgumentsDispatchFunction[this] = it context.mapping.defaultArgumentsOriginalFunction[it] = this @@ -436,7 +452,8 @@ private fun IrFunction.generateDefaultsFunction( skipInlineMethods, skipExternalMethods, forceSetOverrideSymbols, - visibility + visibility, + useConstructorMarker )?.symbol as IrSimpleFunctionSymbol? } } @@ -454,7 +471,7 @@ private fun IrFunction.generateDefaultsFunction( // binaries, it's way too late to fix it. Hence the workaround. if (valueParameters.any { it.defaultValue != null }) { return generateDefaultsFunctionImpl( - context, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER, visibility, isFakeOverride = false + context, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER, visibility, false, useConstructorMarker ).also { context.mapping.defaultArgumentsDispatchFunction[this] = it context.mapping.defaultArgumentsOriginalFunction[it] = this @@ -467,7 +484,8 @@ private fun IrFunction.generateDefaultsFunctionImpl( context: CommonBackendContext, newOrigin: IrDeclarationOrigin, newVisibility: Visibility, - isFakeOverride: Boolean + isFakeOverride: Boolean, + useConstructorMarker: Boolean ): IrFunction { val newFunction = when (this) { is IrConstructor -> @@ -515,7 +533,7 @@ private fun IrFunction.generateDefaultsFunctionImpl( for (i in 0 until (valueParameters.size + 31) / 32) { newFunction.addValueParameter("mask$i".synthesizedString, context.irBuiltIns.intType, IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION) } - if (this is IrConstructor) { + if (useConstructorMarker) { val markerType = context.ir.symbols.defaultConstructorMarker.defaultType.makeNullable() newFunction.addValueParameter("marker".synthesizedString, markerType, IrDeclarationOrigin.DEFAULT_CONSTRUCTOR_MARKER) } else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt index 7c5be4888ce..3e82f658a7e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/DeclarationOrigins.kt @@ -31,6 +31,7 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin { object SYNTHETIC_INLINE_CLASS_MEMBER : IrDeclarationOriginImpl("SYNTHETIC_INLINE_CLASS_MEMBER", isSynthetic = true) object INLINE_CLASS_GENERATED_IMPL_METHOD : IrDeclarationOriginImpl("INLINE_CLASS_GENERATED_IMPL_METHOD") object STATIC_INLINE_CLASS_REPLACEMENT : IrDeclarationOriginImpl("STATIC_INLINE_CLASS_REPLACEMENT") + object STATIC_INLINE_CLASS_CONSTRUCTOR : IrDeclarationOriginImpl("STATIC_INLINE_CLASS_CONSTRUCTOR") object GENERATED_ASSERTION_ENABLED_FIELD : IrDeclarationOriginImpl("GENERATED_ASSERTION_ENABLED_FIELD", isSynthetic = true) object GENERATED_EXTENDED_MAIN : IrDeclarationOriginImpl("GENERATED_EXTENDED_MAIN", isSynthetic = true) object SUSPEND_IMPL_STATIC_FUNCTION : IrDeclarationOriginImpl("SUSPEND_IMPL_STATIC_FUNCTION", isSynthetic = true) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt index 9866e204902..c8eceebd32f 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/CoroutineCodegen.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.LocalDeclarationsLowering import org.jetbrains.kotlin.backend.common.lower.allOverridden import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.coroutines.CoroutineTransformerMethodVisitor @@ -119,9 +120,9 @@ private fun IrFunction.isBridgeToSuspendImplMethod(): Boolean = } private fun IrFunction.isStaticInlineClassReplacementDelegatingCall(): Boolean = - this is IrAttributeContainer && origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT && + this is IrAttributeContainer && !isStaticInlineClassReplacement && parentAsClass.declarations.find { it is IrAttributeContainer && it.attributeOwnerId == attributeOwnerId && it !== this } - ?.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT + ?.isStaticInlineClassReplacement == true internal fun IrFunction.shouldContainSuspendMarkers(): Boolean = !isInvokeSuspendOfContinuation() && // These are tail-call bridges and do not require any bytecode modifications. diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt index 37a770f1d72..c8380e3c6f2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/MethodSignatureMapper.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation import org.jetbrains.kotlin.backend.jvm.ir.isCompiledToJvmDefault +import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal import org.jetbrains.kotlin.builtins.KotlinBuiltIns @@ -35,7 +36,10 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.load.java.* -import org.jetbrains.kotlin.load.kotlin.* +import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.load.kotlin.forceSingleValueParameterBoxing +import org.jetbrains.kotlin.load.kotlin.signatures import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil @@ -314,7 +318,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) { // remapped name or signature and forward to the actually declared method. if (caller.origin == IrDeclarationOrigin.BRIDGE || caller.origin == IrDeclarationOrigin.BRIDGE_SPECIAL) return null // Do not remap calls to static replacements of inline class methods, since they have completely different signatures. - if (callee.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT) return null + if (callee.isStaticInlineClassReplacement) return null val overriddenSpecialBuiltinFunction = callee.descriptor.original.getOverriddenBuiltinReflectingJvmDescriptor() if (overriddenSpecialBuiltinFunction != null && !superCall) { return mapSignatureSkipGeneric(context.referenceFunction(overriddenSpecialBuiltinFunction.original).owner) 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 a488b037c10..a97d9364649 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 @@ -343,3 +343,7 @@ fun IrProperty.needsAccessor(accessor: IrSimpleFunction): Boolean = when { // We do not produce default accessors for private fields else -> accessor.origin != IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR || !Visibilities.isPrivate(accessor.visibility) } + +val IrDeclaration.isStaticInlineClassReplacement: Boolean + get() = origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT + || origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt index 184990f3938..4210f88652d 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/AddContinuationLowering.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.* import org.jetbrains.kotlin.backend.jvm.ir.IrInlineReferenceLocator import org.jetbrains.kotlin.backend.jvm.ir.defaultValue +import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement import org.jetbrains.kotlin.backend.jvm.localDeclarationsPhase import org.jetbrains.kotlin.codegen.coroutines.* import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX @@ -640,7 +641,7 @@ private fun IrFunction.suspendFunctionViewOrStub(context: JvmBackendContext): Ir } internal fun IrFunction.suspendFunctionOriginal(): IrFunction = - if (this is IrSimpleFunction && isSuspend && origin != JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT) + if (this is IrSimpleFunction && isSuspend && !isStaticInlineClassReplacement) attributeOwnerId as IrFunction else this diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultArgumentStubGenerator.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultArgumentStubGenerator.kt index 6c2c8646f0c..b8d5ff8b5bd 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultArgumentStubGenerator.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultArgumentStubGenerator.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.common.lower.irNot import org.jetbrains.kotlin.backend.common.lower.irThrow import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.declarations.* @@ -48,6 +49,9 @@ class JvmDefaultArgumentStubGenerator(override val context: JvmBackendContext) : override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub() + override fun useConstructorMarker(function: IrFunction): Boolean = + function is IrConstructor || function.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR + override fun IrBlockBodyBuilder.generateSuperCallHandlerCheckIfNeeded( irFunction: IrFunction, newIrFunction: IrFunction diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultParameterInjector.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultParameterInjector.kt index 9f59400fa53..61af4736a82 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultParameterInjector.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmDefaultParameterInjector.kt @@ -7,8 +7,10 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.lower.DefaultParameterInjector import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.ir.defaultValue import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub +import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.expressions.IrExpression @@ -27,4 +29,7 @@ class JvmDefaultParameterInjector(context: JvmBackendContext) : } override fun defaultArgumentStubVisibility(function: IrFunction) = function.getJvmVisibilityOfDefaultArgumentStub() + + override fun useConstructorMarker(function: IrFunction): Boolean = + function is IrConstructor || function.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR } 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 8d4c5fbfae2..0302a4a2f80 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 @@ -10,8 +10,10 @@ import org.jetbrains.kotlin.backend.common.ir.copyTypeParameters import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom import org.jetbrains.kotlin.backend.common.ir.createDispatchReceiverParameter import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin +import org.jetbrains.kotlin.backend.jvm.ir.isStaticInlineClassReplacement import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi.mangledNameFor import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.declarations.buildFunWithDescriptorForInlining @@ -45,7 +47,7 @@ class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean) { // Don't mangle anonymous or synthetic functions it.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA || it.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR || - it.origin == JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_REPLACEMENT || + it.isStaticInlineClassReplacement || it.origin.isSynthetic || it.isInlineClassFieldGetter -> null @@ -181,10 +183,17 @@ class MemoizedInlineClassReplacements(private val mangleReturnTypes: Boolean) { body: IrFunctionImpl.() -> Unit ) = buildFunWithDescriptorForInlining(function.descriptor) { updateFrom(function) - origin = if (function.origin == IrDeclarationOrigin.GENERATED_INLINE_CLASS_MEMBER) { - JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD - } else { - replacementOrigin + if (function is IrConstructor) { + // The [updateFrom] call will set the modality to FINAL for constructors, while the JVM backend would use OPEN here. + modality = Modality.OPEN + } + origin = when { + function.origin == IrDeclarationOrigin.GENERATED_INLINE_CLASS_MEMBER -> + JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD + function is IrConstructor && function.constructedClass.isInline -> + JvmLoweredDeclarationOrigin.STATIC_INLINE_CLASS_CONSTRUCTOR + else -> + replacementOrigin } if (noFakeOverride) { isFakeOverride = false diff --git a/compiler/testData/codegen/bytecodeText/constructors/inlinePrimaryDefaults.kt b/compiler/testData/codegen/bytecodeText/constructors/inlinePrimaryDefaults.kt index e77ffe8b07f..2f1b951dac6 100644 --- a/compiler/testData/codegen/bytecodeText/constructors/inlinePrimaryDefaults.kt +++ b/compiler/testData/codegen/bytecodeText/constructors/inlinePrimaryDefaults.kt @@ -1,13 +1,10 @@ +// !LANGUAGE: +InlineClasses +// This tests both KT-37013 and KT-37015. + inline class A(val x: Int = 0) // 0 \(\)V // 1 private synthetic \(I\)V // 1 public final static synthetic box-impl\(I\)LA; - -// JVM_TEMPLATES // 1 public static constructor-impl\(I\)I // 1 public static synthetic constructor-impl\$default\(IILkotlin/jvm/internal/DefaultConstructorMarker;\)I - -// JVM_IR_TEMPLATES -// 1 public final static constructor-impl\(I\)I -// 1 public static synthetic constructor-impl\$default\(IILjava/lang/Object;\)I