diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 9a1d21e4b31..218089a6b0a 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -50459,6 +50459,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/valueClasses/forStatement.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal()); } + @Test + @TestMetadata("functionReferences.kt") + public void testFunctionReferences() throws Exception { + runTest("compiler/testData/codegen/box/valueClasses/functionReferences.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal()); + } + @Test @TestMetadata("mfvcFieldInitializationOrder.kt") public void testMfvcFieldInitializationOrder() throws Exception { diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt index 7e845817f47..7f8b4905de9 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt @@ -24,6 +24,8 @@ import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrValueSymbol import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl @@ -680,8 +682,34 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV } override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { - // todo implement - return super.visitFunctionReference(expression) + val function = expression.symbol.owner + val replacement = function.let { + replacements.run { + getReplacementFunction(it) ?: if (it is IrConstructor) getReplacementForRegularClassConstructor(it) else null + } + } ?: return super.visitFunctionReference(expression) + return if (function is IrConstructor && function.isPrimary && function.constructedClass.isMultiFieldValueClass) { + expression.run { + IrConstructorCallImpl( + startOffset, endOffset, type, function.symbol, typeArgumentsCount, typeArgumentsCount, valueArgumentsCount, origin + ) + }.transform(this, null) + } else { + context.createJvmIrBuilder(getCurrentScopeSymbol()).irBlock { + expression.run { + IrFunctionReferenceImpl( + startOffset, + endOffset, + type, + replacement.symbol, + function.typeParameters.size, + replacement.valueParameters.size, + reflectionTarget, + origin + ) + }.apply { buildReplacement(function, expression, replacement) }.copyAttributes(expression) + }.unwrapBlock() + } } override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression { @@ -1057,7 +1085,12 @@ private class JvmMultiFieldValueClassLowering(context: JvmBackendContext) : JvmV } if (expression is IrTry) { expression.tryResult = irBlock { flattenExpressionTo(expression.tryResult, instance) }.unwrapBlock() - expression.catches.replaceAll { irCatch(it.catchParameter, irBlock { flattenExpressionTo(it.result, instance) }.unwrapBlock()) } + expression.catches.replaceAll { + irCatch( + it.catchParameter, + irBlock { flattenExpressionTo(it.result, instance) }.unwrapBlock() + ) + } expression.finallyExpression = expression.finallyExpression?.transform(lowering, null) +expression return diff --git a/compiler/testData/codegen/box/valueClasses/functionReferences.kt b/compiler/testData/codegen/box/valueClasses/functionReferences.kt new file mode 100644 index 00000000000..c7ea078306e --- /dev/null +++ b/compiler/testData/codegen/box/valueClasses/functionReferences.kt @@ -0,0 +1,33 @@ +// CHECK_BYTECODE_LISTING +// WITH_STDLIB +// TARGET_BACKEND: JVM_IR +// WORKS_WHEN_VALUE_CLASS +// LANGUAGE: +ValueClasses + +@JvmInline +value class DPoint(val x: Double, val y: Double) { + fun f(z: Double) = x + y + z +} + +fun g(point: DPoint, z: Double) = point.f(z) + +class A(val point: DPoint) { + fun f(otherDPoint: DPoint, z: Double) = point.f(z) * otherDPoint.f(z) +} + +fun box(): String { + val dPoint = DPoint(1.0, 2.0) + val a = A(dPoint) + + require((::DPoint)(1.0, 2.0) == dPoint) + require((dPoint::f)(3.0) == 6.0) + require((::g)(dPoint, 3.0) == 6.0) + require((a::f)(dPoint, 3.0) == 36.0) + + require((::DPoint)(1.0, DPoint(1.0, 2.0).y) == dPoint) + require((dPoint::f)(DPoint(1.0, 3.0).y) == 6.0) + require((::g)(dPoint, DPoint(1.0, 3.0).y) == 6.0) + require((a::f)(dPoint, DPoint(1.0, 3.0).y) == 36.0) + + return "OK" +} diff --git a/compiler/testData/codegen/box/valueClasses/functionReferences.txt b/compiler/testData/codegen/box/valueClasses/functionReferences.txt new file mode 100644 index 00000000000..4164c07eaec --- /dev/null +++ b/compiler/testData/codegen/box/valueClasses/functionReferences.txt @@ -0,0 +1,39 @@ +@kotlin.Metadata +public final class A { + // source: 'functionReferences.kt' + private final field point-0: double + private final field point-1: double + public method (p0: double, p1: double): void + public final method f-GPBa7dw(p0: double, p1: double, p2: double): double + public final @org.jetbrains.annotations.NotNull method getPoint(): DPoint + public synthetic final method getPoint-0(): double + public synthetic final method getPoint-1(): double +} + +@kotlin.jvm.JvmInline +@kotlin.Metadata +public final class DPoint { + // source: 'functionReferences.kt' + private final field field-0: double + private final field field-1: double + private synthetic method (p0: double, p1: double): void + public synthetic final static method box-impl(p0: double, p1: double): DPoint + public final static method constructor-impl(p0: double, p1: double): void + public method equals(@org.jetbrains.annotations.Nullable p0: java.lang.Object): boolean + public static method equals-impl(p0: double, p1: double, p2: java.lang.Object): boolean + public final static method equals-impl0(p0: double, p1: double, p2: double, p3: double): boolean + public final static method f-impl(p0: double, p1: double, p2: double): double + public method hashCode(): int + public static method hashCode-impl(p0: double, p1: double): int + public @org.jetbrains.annotations.NotNull method toString(): java.lang.String + public static method toString-impl(p0: double, p1: double): java.lang.String + public synthetic final method unbox-impl-0(): double + public synthetic final method unbox-impl-1(): double +} + +@kotlin.Metadata +public final class FunctionReferencesKt { + // source: 'functionReferences.kt' + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String + public final static method g-GPBa7dw(p0: double, p1: double, p2: double): double +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index af14d91dc25..915297764db 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -50459,6 +50459,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/valueClasses/forStatement.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal()); } + @Test + @TestMetadata("functionReferences.kt") + public void testFunctionReferences() throws Exception { + runTest("compiler/testData/codegen/box/valueClasses/functionReferences.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal()); + } + @Test @TestMetadata("mfvcFieldInitializationOrder.kt") public void testMfvcFieldInitializationOrder() throws Exception {