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 d9a75244561..80d7c8b5177 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 @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin @@ -20,6 +19,7 @@ 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.codegen.PropertyReferenceCodegen +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* @@ -32,10 +32,7 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol -import org.jetbrains.kotlin.ir.types.IrSimpleType -import org.jetbrains.kotlin.ir.types.IrType -import org.jetbrains.kotlin.ir.types.IrTypeProjection -import org.jetbrains.kotlin.ir.types.typeWith +import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid @@ -51,9 +48,7 @@ internal val callableReferencePhase = makeIrFilePhase( // Originally copied from K/Native internal class CallableReferenceLowering(private val context: JvmBackendContext) : FileLoweringPass, IrElementTransformerVoidWithContext() { - // This pass ignores function references used in inline arguments to inline functions references or in SAM conversions. - // We also implicitly ignore all suspend function references by only dealing with subclasses of (K)Function and not - // (K)SuspendFunction. + // This pass ignores suspend function references and function references used in inline arguments to inline functions. private val ignoredFunctionReferences = mutableSetOf() private val IrFunctionReference.isIgnored: Boolean @@ -83,19 +78,6 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) return super.visitFunctionAccess(expression) } - // Ignore function references handled in SAM conversion - override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression { - if (expression.operator == IrTypeOperator.SAM_CONVERSION) { - val invokable = expression.argument - if (invokable is IrFunctionReference) { - ignoredFunctionReferences += invokable - } else if (invokable is IrBlock && invokable.statements.last() is IrFunctionReference) { - ignoredFunctionReferences += invokable.statements.last() as IrFunctionReference - } - } - return super.visitTypeOperator(expression) - } - override fun visitBlock(expression: IrBlock): IrExpression { if (!expression.origin.isLambda) return super.visitBlock(expression) @@ -114,10 +96,31 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) return if (expression.isIgnored) expression else FunctionReferenceBuilder(expression).build() } - private inner class FunctionReferenceBuilder(val irFunctionReference: IrFunctionReference) { - private val isLambda = irFunctionReference.origin.isLambda + // Handle SAM conversions which wrap a function reference: + // class sam$n(private val receiver: R) : Interface { override fun method(...) = receiver.target(...) } + // + // This avoids materializing an invokable KFunction representing, thus producing one less class. + // This is actually very common, as `Interface { something }` is a local function + a SAM-conversion + // of a reference to it into an implementation. + override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression { + if (expression.operator == IrTypeOperator.SAM_CONVERSION) { + val invokable = expression.argument + val reference = if (invokable is IrFunctionReference) { + invokable + } else if (invokable is IrBlock && invokable.origin.isLambda && invokable.statements.last() is IrFunctionReference) { + invokable.statements.dropLast(1).forEach { it.transform(this, null) } + invokable.statements.last() as IrFunctionReference + } else { + return super.visitTypeOperator(expression) + } + reference.transformChildrenVoid() + return FunctionReferenceBuilder(reference, expression.typeOperand).build() + } + return super.visitTypeOperator(expression) + } - private val functionReferenceOrLambda = if (isLambda) context.ir.symbols.lambdaClass else context.ir.symbols.functionReference + private inner class FunctionReferenceBuilder(val irFunctionReference: IrFunctionReference, val samSuperType: IrType? = null) { + private val isLambda = irFunctionReference.origin.isLambda private val callee = irFunctionReference.symbol.owner @@ -133,38 +136,46 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) private val typeArgumentsMap = irFunctionReference.typeSubstitutionMap + private val functionSuperClass = + samSuperType?.classOrNull ?: context.ir.symbols.getJvmFunctionClass(argumentTypes.size) + private val superMethod = + functionSuperClass.functions.single { it.owner.modality == Modality.ABSTRACT } + private val superType = + samSuperType ?: (if (isLambda) context.ir.symbols.lambdaClass else context.ir.symbols.functionReference).owner.typeWith() + private val functionReferenceClass = buildClass { setSourceRange(irFunctionReference) visibility = Visibilities.LOCAL // A callable reference results in a synthetic class, while a lambda is not synthetic. + // We don't produce GENERATED_SAM_IMPLEMENTATION, which is always synthetic. origin = if (isLambda) JvmLoweredDeclarationOrigin.LAMBDA_IMPL else JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL name = Name.special("") }.apply { parent = currentDeclarationParent - superTypes += functionReferenceOrLambda.owner.defaultType + superTypes += superType + if (samSuperType == null) + superTypes += functionSuperClass.typeWith(parameterTypes) createImplicitParameterDeclarationWithWrappedDescriptor() copyAttributes(irFunctionReference) } - fun build(): IrExpression { + fun build(): IrExpression = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).irBlock { val constructor = createConstructor() - val invokeMethod = createInvokeMethod() + createInvokeMethod( + if (samSuperType != null && boundReceiver != null) { + irTemporary(boundReceiver.second) + } else null + ) - val functionClass = context.ir.symbols.getJvmFunctionClass(argumentTypes.size) - functionReferenceClass.superTypes += functionClass.typeWith(parameterTypes) - invokeMethod.overriddenSymbols += functionClass.functions.single { it.owner.name.asString() == "invoke" } - - if (!isLambda) { + if (!isLambda && samSuperType == null) { createGetSignatureMethod(functionGetSignature) createGetNameMethod(functionGetName) createGetOwnerMethod(functionGetOwner) } - return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).irBlock(irFunctionReference) { - +functionReferenceClass - +irCall(constructor.symbol).apply { - boundReceiver?.second?.let { putValueArgument(0, it) } - } + +functionReferenceClass + +irCall(constructor.symbol).apply { + if (valueArgumentsCount > 0) putValueArgument(0, boundReceiver!!.second) } } @@ -176,39 +187,49 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) isPrimary = true }.apply { // Add receiver parameter for bound function references - boundReceiver?.first?.let { param -> - valueParameters += param.copyTo( - irFunction = this, - index = valueParameters.size, - type = param.type.substitute(typeArgumentsMap) - ) + if (samSuperType == null) { + boundReceiver?.first?.let { param -> + valueParameters += param.copyTo( + irFunction = this, + index = 0, + type = param.type.substitute(typeArgumentsMap) + ) + } } // Super constructor: + // - For SAM references, the super class is Any // - For function references with bound receivers, accepts arity and receiver // - For lambdas and function references without bound receivers, accepts arity - val kFunctionRefConstructor = functionReferenceOrLambda.owner.constructors.single { - it.valueParameters.size == if (boundReceiver != null) 2 else 1 + val constructor = if (samSuperType != null) { + context.irBuiltIns.anyClass.owner.constructors.single() + } else { + superType.getClass()!!.constructors.single { + it.valueParameters.size == if (boundReceiver != null) 2 else 1 + } } body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { - +irDelegatingConstructorCall(kFunctionRefConstructor).apply { - putValueArgument(0, irInt(argumentTypes.size)) - if (boundReceiver != null) - putValueArgument(1, irGet(valueParameters.first())) + +irDelegatingConstructorCall(constructor).apply { + if (samSuperType == null) { + putValueArgument(0, irInt(argumentTypes.size)) + if (boundReceiver != null) + putValueArgument(1, irGet(valueParameters.first())) + } } +IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, context.irBuiltIns.unitType) } } - private fun createInvokeMethod(): IrSimpleFunction = + private fun createInvokeMethod(receiverVar: IrValueDeclaration?): IrSimpleFunction = functionReferenceClass.addFunction { - name = Name.identifier("invoke") + name = superMethod.owner.name returnType = callee.returnType isSuspend = callee.isSuspend }.apply { + overriddenSymbols += superMethod dispatchReceiverParameter = parentAsClass.thisReceiver!!.copyTo(this) - if (isLambda) createLambdaInvokeMethod() else createFunctionReferenceInvokeMethod() + if (isLambda) createLambdaInvokeMethod() else createFunctionReferenceInvokeMethod(receiverVar) } // Inline the body of an anonymous function into the generated lambda subclass. @@ -248,7 +269,7 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) } } - private fun IrSimpleFunction.createFunctionReferenceInvokeMethod() { + private fun IrSimpleFunction.createFunctionReferenceInvokeMethod(receiver: IrValueDeclaration?) { for ((index, argumentType) in argumentTypes.withIndex()) { addValueParameter { name = Name.identifier("p$index") @@ -266,22 +287,31 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) for (parameter in callee.explicitParameters) { when { boundReceiver?.first == parameter -> - // Bound receiver parameter - irImplicitCast( - irGetField(irGet(dispatchReceiverParameter!!), functionReferenceReceiverField), - boundReceiver.second.type - ) + // Bound receiver parameter. For function references, this is stored in a field of the superclass. + // For sam references, we just capture the value in a local variable and LocalDeclarationsLowering + // will put it into a field. + if (samSuperType == null) + irImplicitCast( + irGetField(irGet(dispatchReceiverParameter!!), functionReferenceReceiverField), + boundReceiver.second.type + ) + else + irGet(receiver!!) // If a vararg parameter corresponds to exactly one KFunction argument, which is an array, that array - // is forwarded as is. In all other cases, excess arguments are packed into a new array. + // is forwarded as is. // // fun f(x: (Int, Array) -> String) = x(0, arrayOf("OK", "FAIL")) - // fun g(x: (Int, String, String) -> String) = x(0, "OK", "FAIL") // fun h(i: Int, vararg xs: String) = xs[i] - // f(::h) == g(::h) + // f(::h) // parameter.isVararg && unboundIndex < argumentTypes.size && parameter.type == valueParameters[unboundIndex].type -> - irArray(parameter.type) { addSpread(irGet(valueParameters[unboundIndex++])) } + irGet(valueParameters[unboundIndex++]) + // In all other cases, excess arguments are packed into a new array. + // + // fun g(x: (Int, String, String) -> String) = x(0, "OK", "FAIL") + // f(::h) == g(::h) + // parameter.isVararg && (unboundIndex < argumentTypes.size || !parameter.hasDefaultValue()) -> irArray(parameter.type) { (unboundIndex until argumentTypes.size).forEach { +irGet(valueParameters[unboundIndex++]) } @@ -341,11 +371,7 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext) companion object { private fun IrBuilderWithScope.kClassReference(classType: IrType) = IrClassReferenceImpl( - startOffset, - endOffset, - context.irBuiltIns.kClassClass.typeWith(), - context.irBuiltIns.kClassClass, - classType + startOffset, endOffset, context.irBuiltIns.kClassClass.typeWith(), context.irBuiltIns.kClassClass, classType ) private fun IrBuilderWithScope.kClassToJavaClass(kClassReference: IrExpression, context: JvmBackendContext) = 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 1274fe70142..ae21497c7b4 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 @@ -20,8 +20,12 @@ 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.* -import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer +import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.copyAttributes +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrTypeOperator +import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.classifierOrFail @@ -44,7 +48,6 @@ internal val singleAbstractMethodPhase = makeIrFilePhase( class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLoweringPass { override fun lower(irClass: IrClass) { val cachedImplementations = mutableMapOf, IrClass>() - val localImplementations = mutableListOf() irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression { if (expression.operator != IrTypeOperator.SAM_CONVERSION) @@ -53,32 +56,32 @@ class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLow val invokable = expression.argument.transform(this, null) // Running in the class context, so empty scope means this is a field/anonymous initializer. val scopeOwnerSymbol = currentScope?.scope?.scopeOwnerSymbol ?: irClass.symbol - return context.createIrBuilder(scopeOwnerSymbol).irBlock(invokable, null, superType) { - // Not an exhaustive check, but enough to cover the most common cases. - if (invokable is IrFunctionReference) { - // Runnable(::function) - +createFunctionProxyInstance(superType, invokable) - } else if (invokable is IrBlock && invokable.statements.last() is IrFunctionReference) { - // Runnable { lambda } - for (statement in invokable.statements.dropLast(1)) - +statement - +createFunctionProxyInstance(superType, invokable.statements.last() as IrFunctionReference) + context.createIrBuilder(scopeOwnerSymbol).apply { + // 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, expression) + } + + return if (superType.isNullable() && invokable.type.isNullable()) { + irBlock(invokable, null, superType) { + val invokableVariable = irTemporary(invokable) + val instance = irCall(implementation.constructors.single()).apply { + putValueArgument(0, irGet(invokableVariable)) + } + irIfNull(superType, irGet(invokableVariable), irNull(), instance) + } } else { - // Fall back to materializing an invokable object. - +createObjectProxyInstance(superType, invokable, expression) + irCall(implementation.constructors.single()).apply { putValueArgument(0, invokable) } } } } - // Construct a class that implements the specified SAM interface and contains a bunch of fields - // in which the arguments to the constructor are stored: - // class sam$n(private val arg0: T0, ...) { override fun method(...) = } - private fun implement( - superType: IrType, - parameters: List, - attributeOwner: IrAttributeContainer, - buildOverride: IrSimpleFunction.(List) -> IrBody - ): IrClass { + // 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, attributeOwner: IrAttributeContainer): IrClass { val superClass = superType.classifierOrFail.owner as IrClass // The language documentation prohibits casting lambdas to classes, but if it was allowed, // the `irDelegatingConstructorCall` in the constructor below would need to be modified. @@ -94,30 +97,26 @@ class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLow superTypes += superType }.copyAttributes(attributeOwner) - val fields = parameters.mapIndexed { i, fieldType -> - subclass.addField { - name = Name.identifier("arg$i") - type = fieldType - origin = subclass.origin - visibility = Visibilities.PRIVATE - } + val field = subclass.addField { + name = Name.identifier("arg0") + type = invokableType + origin = subclass.origin + visibility = Visibilities.PRIVATE } subclass.addConstructor { origin = subclass.origin isPrimary = true }.apply { - for (field in fields) { - addValueParameter { - name = field.name - type = field.type - origin = subclass.origin - } + val parameter = addValueParameter { + name = field.name + type = field.type + origin = subclass.origin } + body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { +irDelegatingConstructorCall(context.irBuiltIns.anyClass.owner.constructors.single()) - for ((field, parameter) in fields.zip(valueParameters)) - +irSetField(irGet(subclass.thisReceiver!!), field, irGet(parameter)) + +irSetField(irGet(subclass.thisReceiver!!), field, irGet(parameter)) +IrInstanceInitializerCallImpl(startOffset, endOffset, subclass.symbol, context.irBuiltIns.unitType) } } @@ -129,102 +128,21 @@ class SingleAbstractMethodLowering(val context: CommonBackendContext) : ClassLow visibility = superMethod.visibility origin = subclass.origin }.apply { - overriddenSymbols.add(superMethod.symbol) + overriddenSymbols += superMethod.symbol dispatchReceiverParameter = subclass.thisReceiver!!.copyTo(this) superMethod.valueParameters.mapTo(valueParameters) { it.copyTo(this) } - body = buildOverride(fields) - } - - return subclass - } - - // 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, 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 { - dispatchReceiver = irGetField(irGet(dispatchReceiverParameter!!), fields[0]) + val invokableClass = invokableType.classifierOrFail.owner as IrClass + body = context.createIrBuilder(symbol).run { + irExprBody(irCall(invokableClass.functions.single { it.name == OperatorNameConventions.INVOKE }).apply { + dispatchReceiver = irGetField(irGet(dispatchReceiverParameter!!), field) valueParameters.forEachIndexed { i, parameter -> putValueArgument(i, irGet(parameter)) } }) } } - 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, attributeOwner) - } - return if (superType.isNullable() && invokable.type.isNullable()) { - val invokableVariable = irTemporary(invokable) - val instance = irCall(implementation.constructors.single()).apply { putValueArgument(0, irGet(invokableVariable)) } - irIfNull(superType, irGet(invokableVariable), irNull(), instance) - } else { - irCall(implementation.constructors.single()).apply { putValueArgument(0, invokable) } - } - } - - // This lowering is located after LocalDeclarationsLowering. On the one hand, this allows us to cache - // object-wrapping classes without checking if the types are local declarations or not. On the other hand, - // this means we need to manually create fields for all bound arguments when wrapping callable references. - private val IrFunctionReference.arguments: List - get() = listOf(dispatchReceiver).filter { symbol.owner.dispatchReceiverParameter != null } + - listOf(extensionReceiver).filter { symbol.owner.extensionReceiverParameter != null } + - (0 until valueArgumentsCount).map(::getValueArgument) - - // Construct a class that forwards method calls to an existing function/method: - // class sam$n(private val receiver: R) : Interface { override fun method(...) = receiver.target(...) } - // - // Unlike the above variant, this avoids materializing an invokable KFunction representing - // the target in CallableReferenceLowering, thus producing one less class. This is actually very - // 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 }, reference) { fields -> - context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { - +irReturn(irCall(reference.symbol).apply { - var boundOffset = 0 - var offset = 0 - val arguments = reference.arguments.map { - if (it != null) - irGetField(irGet(dispatchReceiverParameter!!), fields[boundOffset++]) - else - irGet(valueParameters[offset++]) - }.toMutableList() - if (reference.symbol.owner.dispatchReceiverParameter != null) { - dispatchReceiver = arguments.removeAt(0) - } - if (reference.symbol.owner.extensionReceiverParameter != null) { - extensionReceiver = arguments.removeAt(0) - } - arguments.forEachIndexed(::putValueArgument) - }) - } - } - - private fun IrBlockBuilder.createFunctionProxyInstance(superType: IrType, reference: IrFunctionReference): IrExpression { - val implementation = createFunctionProxy(superType, reference) - if (reference.origin == IrStatementOrigin.ANONYMOUS_FUNCTION || reference.origin == IrStatementOrigin.LAMBDA) { - val target = reference.symbol.owner - implementation.functions.single().apply { - annotations.addAll(target.annotations) - valueParameters.forEachIndexed { i, p -> - p.annotations.addAll(target.valueParameters[i].annotations) - } - } - } - localImplementations += implementation - return irCall(implementation.constructors.single()).apply { - reference.arguments.filterNotNull().forEachIndexed(::putValueArgument) - } + return subclass } }) irClass.declarations += cachedImplementations.values - irClass.declarations += localImplementations } } diff --git a/compiler/testData/codegen/box/reflection/enclosing/kt6691_lambdaInSamConstructor.kt b/compiler/testData/codegen/box/reflection/enclosing/kt6691_lambdaInSamConstructor.kt index ad88f5340c6..7196997421a 100644 --- a/compiler/testData/codegen/box/reflection/enclosing/kt6691_lambdaInSamConstructor.kt +++ b/compiler/testData/codegen/box/reflection/enclosing/kt6691_lambdaInSamConstructor.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT