From 1abdcf3f574cffc6895f51f9c5032cac02db829a Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Tue, 24 Sep 2019 20:52:02 +0300 Subject: [PATCH] JVM_IR: support function references with default parameters --- .../kotlin/backend/common/ir/IrUtils.kt | 4 ++- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 2 +- .../lower/InlineCallableReferenceToLambda.kt | 28 +++++++++++++++++-- .../box/defaultArguments/referenceAsArg.kt | 8 ++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 ++++ .../LightAnalysisModeTestGenerated.java | 5 ++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 ++++ .../IrJsCodegenBoxTestGenerated.java | 5 ++++ .../semantics/JsCodegenBoxTestGenerated.java | 5 ++++ 9 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/box/defaultArguments/referenceAsArg.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index bf34e6ff7c4..32036c3e0ff 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -231,7 +231,8 @@ private fun IrTypeParameter.copySuperTypesFrom(source: IrTypeParameter) { fun IrFunction.copyValueParametersToStatic( source: IrFunction, origin: IrDeclarationOrigin, - dispatchReceiverType: IrType? = source.dispatchReceiverParameter?.type + dispatchReceiverType: IrType? = source.dispatchReceiverParameter?.type, + numValueParametersToCopy: Int = source.valueParameters.size ) { val target = this assert(target.valueParameters.isEmpty()) @@ -266,6 +267,7 @@ fun IrFunction.copyValueParametersToStatic( } for (oldValueParameter in source.valueParameters) { + if (oldValueParameter.index >= numValueParametersToCopy) break target.valueParameters.add( oldValueParameter.copyTo( target, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 1a798b1201f..58946165b43 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -141,7 +141,7 @@ private val defaultArgumentInjectorPhase = makeIrFilePhase( ::JvmDefaultParameterInjector, name = "DefaultParameterInjector", description = "Transform calls with default arguments into calls to stubs", - prerequisite = setOf(defaultArgumentStubPhase, callableReferencePhase) + prerequisite = setOf(defaultArgumentStubPhase, callableReferencePhase, inlineCallableReferenceToLambdaPhase) ) private val interfacePhase = makeIrFilePhase( diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt index 2c3ddc59581..1bb024d79ee 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/InlineCallableReferenceToLambda.kt @@ -27,8 +27,11 @@ 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.IrFunctionReferenceImpl -import org.jetbrains.kotlin.ir.util.defaultType -import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.types.isSubtypeOf +import org.jetbrains.kotlin.ir.types.isSubtypeOfClass +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name @@ -141,7 +144,24 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte val irBuilder = context.createIrBuilder(scope.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset) + val boundReceiver = expression.dispatchReceiver ?: expression.extensionReceiver + + val expectedType = expression.type + var expectedNumValueParameters: Int + if (expectedType.isFunctionOrKFunction() || expectedType.isSuspendFunction() || expectedType.isKSuspendFunction()) { // TODO: handle subtypes + expectedNumValueParameters = (expectedType as IrSimpleType).arguments.size - 1 // In ...Function classes, the last argument is return type + referencedFunction.dispatchReceiverParameter?.let { expectedNumValueParameters-- } + referencedFunction.extensionReceiverParameter?.let { expectedNumValueParameters-- } + boundReceiver?.let { expectedNumValueParameters++ } + assert(referencedFunction.valueParameters.subList(expectedNumValueParameters, referencedFunction.valueParameters.size).all { + it.defaultValue != null + }) + } else { + assert(expectedType.classOrNull?.isSubtypeOfClass(context.irBuiltIns.kPropertyClass) == true) + expectedNumValueParameters = 0 + } + return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) { lateinit var variableForBoundReceiver: IrVariable if (boundReceiver != null) { @@ -161,9 +181,10 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte } copyTypeParametersFrom(referencedFunction) if (boundReceiver == null) { - copyValueParametersToStatic(referencedFunction, origin) + copyValueParametersToStatic(referencedFunction, origin, numValueParametersToCopy = expectedNumValueParameters) } else { for (oldValueParameter in referencedFunction.valueParameters) { + if (oldValueParameter.index >= expectedNumValueParameters) break valueParameters.add( oldValueParameter.copyTo( this, @@ -197,6 +218,7 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte } for (it in referencedFunction.valueParameters.indices) { + if (it >= expectedNumValueParameters) break call.putValueArgument(it, irGet(valueParameters[shift++])) } } diff --git a/compiler/testData/codegen/box/defaultArguments/referenceAsArg.kt b/compiler/testData/codegen/box/defaultArguments/referenceAsArg.kt new file mode 100644 index 00000000000..162b3dfa5d9 --- /dev/null +++ b/compiler/testData/codegen/box/defaultArguments/referenceAsArg.kt @@ -0,0 +1,8 @@ +// !LANGUAGE: +NewInference +FunctionReferenceWithDefaultValueAsOtherType +// IGNORE_BACKEND: JS_IR + +inline fun String.app(f: (String) -> String) = f(this) + +fun fff(s: String, n: Int = 42) = s + +fun box() = "OK".app(::fff) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 7acf1513ad5..4feb7a5594f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -8982,6 +8982,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/defaultArguments/protected.kt"); } + @TestMetadata("referenceAsArg.kt") + public void testReferenceAsArg() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/referenceAsArg.kt"); + } + @TestMetadata("simpleFromOtherFile.kt") public void testSimpleFromOtherFile() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/simpleFromOtherFile.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 7bd5f7fb89f..5f53d35ddf8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -8982,6 +8982,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/defaultArguments/protected.kt"); } + @TestMetadata("referenceAsArg.kt") + public void testReferenceAsArg() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/referenceAsArg.kt"); + } + @TestMetadata("simpleFromOtherFile.kt") public void testSimpleFromOtherFile() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/simpleFromOtherFile.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 9c89922d905..742b08a46d5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7867,6 +7867,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/defaultArguments/protected.kt"); } + @TestMetadata("referenceAsArg.kt") + public void testReferenceAsArg() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/referenceAsArg.kt"); + } + @TestMetadata("simpleFromOtherFile.kt") public void testSimpleFromOtherFile() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/simpleFromOtherFile.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 45fdeda8c71..1c037bf1edd 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -6717,6 +6717,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/defaultArguments/protected.kt"); } + @TestMetadata("referenceAsArg.kt") + public void testReferenceAsArg() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/referenceAsArg.kt"); + } + @TestMetadata("simpleFromOtherFile.kt") public void testSimpleFromOtherFile() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/simpleFromOtherFile.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 5f2c6eeac3a..e7297be060d 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -7802,6 +7802,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/defaultArguments/protected.kt"); } + @TestMetadata("referenceAsArg.kt") + public void testReferenceAsArg() throws Exception { + runTest("compiler/testData/codegen/box/defaultArguments/referenceAsArg.kt"); + } + @TestMetadata("simpleFromOtherFile.kt") public void testSimpleFromOtherFile() throws Exception { runTest("compiler/testData/codegen/box/defaultArguments/simpleFromOtherFile.kt");