JVM_IR: support function references with default parameters

This commit is contained in:
Georgy Bronnikov
2019-09-24 20:52:02 +03:00
parent 1a7f1dff10
commit 1abdcf3f57
9 changed files with 62 additions and 5 deletions
@@ -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,
@@ -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(
@@ -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++]))
}
}
@@ -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)
@@ -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");
@@ -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");
@@ -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");
@@ -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");
@@ -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");