From 963258189a36a9866b4e483628653cba4e8a1776 Mon Sep 17 00:00:00 2001 From: Georgy Bronnikov Date: Fri, 21 Feb 2020 20:41:04 +0300 Subject: [PATCH] JVM_IR: change parameter type computation in InlineCallableReferenceToLambda The reference type is approximated in Psi2Ir, so we may get Nothing as a reference type argument. Better look at the arguments of the referenced function. --- .../lower/InlineCallableReferenceToLambda.kt | 18 ++++++++++++++---- .../function/argumentTypes.kt | 12 ++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 5 +++++ .../LightAnalysisModeTestGenerated.java | 5 +++++ .../ir/FirBlackBoxCodegenTestGenerated.java | 5 +++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 +++++ .../semantics/IrJsCodegenBoxTestGenerated.java | 5 +++++ .../semantics/JsCodegenBoxTestGenerated.java | 5 +++++ 8 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/box/callableReference/function/argumentTypes.kt 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 8c86ce9e85b..5376b8f8223 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 @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.jvm.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.ir.allParameters import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase @@ -25,7 +26,6 @@ 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.types.IrSimpleType -import org.jetbrains.kotlin.ir.types.IrTypeProjection import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name @@ -117,10 +117,20 @@ internal class InlineCallableReferenceToLambdaPhase(val context: JvmBackendConte val irBuilder = context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset) return irBuilder.irBlock(expression, IrStatementOrigin.LAMBDA) { - val parameterTypes = (expression.type as IrSimpleType).arguments.map { (it as IrTypeProjection).type } - val argumentTypes = parameterTypes.dropLast(1) - + // We find the number of parameters for constructed lambda from the type of the function reference, + // but the actual types have to be copied from referencedFunction; function reference argument type may be too + // specific because of approximation. See compiler/testData/codegen/box/callableReference/function/argumentTypes.kt val boundReceiver: Pair? = expression.getArgumentsWithIr().singleOrNull() + val nParams = (expression.type as IrSimpleType).arguments.size - 1 + var toDropAtStart = 0 + if (boundReceiver != null) toDropAtStart++ + if (referencedFunction is IrConstructor) toDropAtStart++ + val argumentTypes = referencedFunction.allParameters.drop(toDropAtStart).take(nParams).map { parameter -> + parameter.type.substitute( + referencedFunction.typeParameters, + referencedFunction.typeParameters.indices.map { expression.getTypeArgument(it)!! } + ) + } val function = buildFun { setSourceRange(expression) diff --git a/compiler/testData/codegen/box/callableReference/function/argumentTypes.kt b/compiler/testData/codegen/box/callableReference/function/argumentTypes.kt new file mode 100644 index 00000000000..1a1413ac420 --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/function/argumentTypes.kt @@ -0,0 +1,12 @@ +// IGNORE_BACKEND_FIR: JVM_IR +inline fun id(x: TT): TT = x +inline fun String.extId(x: TT): String = this + +private fun ff(value: T?): String { + // In PSI2IR, the funcref is approximated to Function1> + value?.let(::id) + return value?.let("OK"::extId)!! +} + +fun box() = ff("arg") + diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index b80f1041534..120175c50fa 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -2186,6 +2186,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/function"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("argumentTypes.kt") + public void testArgumentTypes() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/function/argumentTypes.kt"); + } + @TestMetadata("booleanNotIntrinsic.kt") public void testBooleanNotIntrinsic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 7301c4c9f06..6aa9fed1822 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -2186,6 +2186,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/function"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); } + @TestMetadata("argumentTypes.kt") + public void testArgumentTypes() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/function/argumentTypes.kt"); + } + @TestMetadata("booleanNotIntrinsic.kt") public void testBooleanNotIntrinsic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index b4d527d7904..c1e516d0e5d 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -2166,6 +2166,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/function"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("argumentTypes.kt") + public void testArgumentTypes() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/function/argumentTypes.kt"); + } + @TestMetadata("booleanNotIntrinsic.kt") public void testBooleanNotIntrinsic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 6051f8c37c4..408d4318990 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -2166,6 +2166,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/function"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); } + @TestMetadata("argumentTypes.kt") + public void testArgumentTypes() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/function/argumentTypes.kt"); + } + @TestMetadata("booleanNotIntrinsic.kt") public void testBooleanNotIntrinsic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.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 5cf63f80546..14253c81e53 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 @@ -1596,6 +1596,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/function"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); } + @TestMetadata("argumentTypes.kt") + public void testArgumentTypes() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/function/argumentTypes.kt"); + } + @TestMetadata("booleanNotIntrinsic.kt") public void testBooleanNotIntrinsic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.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 995819e38c0..0f8df5fbfb2 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 @@ -1596,6 +1596,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/callableReference/function"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); } + @TestMetadata("argumentTypes.kt") + public void testArgumentTypes() throws Exception { + runTest("compiler/testData/codegen/box/callableReference/function/argumentTypes.kt"); + } + @TestMetadata("booleanNotIntrinsic.kt") public void testBooleanNotIntrinsic() throws Exception { runTest("compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.kt");