diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InventNamesForLocalClasses.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InventNamesForLocalClasses.kt index 28ef3cca083..04f816fab6c 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InventNamesForLocalClasses.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InventNamesForLocalClasses.kt @@ -11,9 +11,9 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.expressions.IrPropertyReference +import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.isAnonymousObject import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.name.Name @@ -160,6 +160,27 @@ class InventNamesForLocalClasses(private val context: JvmBackendContext) : FileL declaration.acceptChildren(this, data.makeLocal()) } + override fun visitTypeOperator(expression: IrTypeOperatorCall, data: Data) { + if (expression.operator == IrTypeOperator.SAM_CONVERSION) { + val invokable = expression.argument + // Function references (even those that are transformed into SAM wrappers) are handled in visitFunctionReference. + if (invokable !is IrFunctionReference && !(invokable is IrBlock && invokable.statements.last() is IrFunctionReference)) { + val superClass = expression.typeOperandClassifier.owner as IrClass + val superClassName = superClass.fqNameWhenAvailable!!.pathSegments().joinToString("_") { it.toString() } + + // TODO: consider dropping "sam\$$superClassName$0" from the name here. + // It's only here to give resemblance of the name generated for SAM wrappers by the old backend. The exact logic + // of the old backend is somewhat difficult to emulate consistently, see `SamWrapperCodegen.getWrapperName`. + val internalName = inventName(Name.identifier("sam\$$superClassName$0"), data) + context.putLocalClassInfo(expression, JvmBackendContext.LocalClassInfo(internalName)) + invokable.accept(this, data.withName(internalName)) + return + } + } + + expression.acceptChildren(this, data) + } + override fun visitElement(element: IrElement, data: Data) { element.acceptChildren(this, data) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingleAbstractMethodLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingleAbstractMethodLowering.kt index b74a07fcd9a..10302b5ad69 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingleAbstractMethodLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/SingleAbstractMethodLowering.kt @@ -19,9 +19,7 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.* -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrField -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.types.IrType @@ -65,7 +63,7 @@ class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLow +createFunctionProxyInstance(superType, invokable.statements.last() as IrFunctionReference) } else { // Fall back to materializing an invokable object. - +createObjectProxyInstance(superType, invokable) + +createObjectProxyInstance(superType, invokable, expression) } } } @@ -76,6 +74,7 @@ class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLow private fun implement( superType: IrType, parameters: List, + attributeOwner: IrAttributeContainer, buildOverride: IrSimpleFunction.(List) -> IrBody ): IrClass { val superClass = superType.classifierOrFail.owner as IrClass @@ -83,17 +82,15 @@ class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLow // the `irDelegatingConstructorCall` in the constructor below would need to be modified. assert(superClass.kind == ClassKind.INTERFACE) { "SAM conversion to an abstract class not allowed" } - val superClassName = superClass.fqNameWhenAvailable!!.pathSegments().joinToString("_") { it.toString() } val subclass = buildClass { - // TODO this is not the name some tests (e.g. kt11519) expect - name = Name.identifier("sam\$$superClassName\$${cachedImplementations.size + localImplementations.size}") + name = Name.special("") origin = JvmLoweredDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION }.apply { createImplicitParameterDeclarationWithWrappedDescriptor() parent = irClass // TODO convert all type parameters to upper bounds? See the kt11696 test. superTypes += superType - } + }.copyAttributes(attributeOwner) val fields = parameters.mapIndexed { i, fieldType -> subclass.addField { @@ -141,8 +138,8 @@ class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLow // Construct a class that wraps an invokable object into an implementation of an interface: // class sam$n(private val invokable: F) : Interface { override fun method(...) = invokable(...) } - private fun createObjectProxy(superType: IrType, invokableType: IrType): IrClass = - implement(superType, listOf(invokableType)) { fields -> + private fun createObjectProxy(superType: IrType, invokableType: IrType, attributeOwner: IrAttributeContainer): IrClass = + implement(superType, listOf(invokableType), attributeOwner) { fields -> context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { val invokableClass = invokableType.classifierOrFail.owner as IrClass +irReturn(irCall(invokableClass.functions.single { it.name == OperatorNameConventions.INVOKE }).apply { @@ -152,12 +149,14 @@ class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLow } } - private fun IrBlockBuilder.createObjectProxyInstance(superType: IrType, invokable: IrExpression): IrExpression { + private fun IrBlockBuilder.createObjectProxyInstance( + superType: IrType, invokable: IrExpression, attributeOwner: IrAttributeContainer + ): IrExpression { // Do not generate a wrapper class for null, it has no invoke() anyway. if (invokable.isNullConst()) return invokable val implementation = cachedImplementations.getOrPut(superType to invokable.type) { - createObjectProxy(superType, invokable.type) + createObjectProxy(superType, invokable.type, attributeOwner) } return if (superType.isNullable() && invokable.type.isNullable()) { val invokableVariable = irTemporary(invokable) @@ -184,7 +183,7 @@ class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLow // common, as `Interface { something }` is a local function + a SAM-conversion of a reference // to it into an implementation. private fun createFunctionProxy(superType: IrType, reference: IrFunctionReference): IrClass = - implement(superType, reference.arguments.mapNotNull { it?.type }) { fields -> + implement(superType, reference.arguments.mapNotNull { it?.type }, reference) { fields -> context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { +irReturn(irCall(reference.symbol).apply { var boundOffset = 0