diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index d5080254a81..3f761586ad7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -413,9 +413,19 @@ class MethodInliner( val capturedParamsSize = parameters.capturedParametersSizeOnStack val realParametersSize = parameters.realParametersSizeOnStack + val reorderIrLambdaParameters = inliningContext.isInliningLambda && + inliningContext.parent?.isInliningLambda == false && + inliningContext.lambdaInfo is IrExpressionLambda + val newArgumentList = if (reorderIrLambdaParameters) { + // In IR lambdas, captured variables come before real parameters, but after the extension receiver. + // Move them to the end of the descriptor instead. + Type.getArgumentTypes(inliningContext.lambdaInfo!!.invokeMethod.descriptor) + parameters.capturedTypes + } else { + Type.getArgumentTypes(node.desc) + parameters.capturedTypes + } val transformedNode = MethodNode( Opcodes.API_VERSION, node.access, node.name, - Type.getMethodDescriptor(Type.getReturnType(node.desc), *(Type.getArgumentTypes(node.desc) + parameters.capturedTypes)), + Type.getMethodDescriptor(Type.getReturnType(node.desc), *newArgumentList), node.signature, node.exceptions?.toTypedArray() ) @@ -426,19 +436,21 @@ class MethodInliner( private fun getNewIndex(`var`: Int): Int { val lambdaInfo = inliningContext.lambdaInfo - if (inliningContext.isInliningLambda && lambdaInfo is IrExpressionLambda) { - if (`var` < parameters.argsSizeOnStack) { - val capturedParamsStartIndex = - if (lambdaInfo.isExtensionLambda) lambdaInfo.invokeMethod.argumentTypes[0].size else 0 //shift by extension - val capturedParamsEndIndex = capturedParamsSize + capturedParamsStartIndex - 1 - if (`var` in capturedParamsStartIndex..capturedParamsEndIndex) { - return `var` + realParametersSize - capturedParamsStartIndex //subtract extension - } else if (`var` >= capturedParamsStartIndex) { - return `var` - capturedParamsSize - } + if (reorderIrLambdaParameters && lambdaInfo is IrExpressionLambda) { + val extensionSize = if (lambdaInfo.isExtensionLambda) lambdaInfo.invokeMethod.argumentTypes[0].size else 0 + return when { + // v-- extensionSize v-- argsSizeOnStack + // |- extension -|- captured -|- real -|- locals -| old descriptor + // |- extension -|- real -|- captured -|- locals -| new descriptor + // ^-- realParametersSize + `var` >= parameters.argsSizeOnStack -> `var` + `var` >= extensionSize + capturedParamsSize -> `var` - capturedParamsSize + `var` >= extensionSize -> `var` + realParametersSize - extensionSize + else -> `var` } - return `var` } + // |- extension -|- real -|- locals -| old descriptor + // |- extension -|- real -|- captured -|- locals -| new descriptor return `var` + if (`var` < realParametersSize) 0 else capturedParamsSize } diff --git a/compiler/testData/codegen/box/unsignedTypes/unsignedRangeIterator.kt b/compiler/testData/codegen/box/unsignedTypes/unsignedRangeIterator.kt index 6bb97554679..a3f547cf1cb 100644 --- a/compiler/testData/codegen/box/unsignedTypes/unsignedRangeIterator.kt +++ b/compiler/testData/codegen/box/unsignedTypes/unsignedRangeIterator.kt @@ -1,6 +1,5 @@ // KJS_WITH_FULL_RUNTIME // WITH_RUNTIME -// IGNORE_BACKEND: JVM_IR fun testUIntRangeForEach() { var s = 0 diff --git a/compiler/testData/codegen/boxInline/simple/captureAndArgumentIncompatibleTypes.kt b/compiler/testData/codegen/boxInline/simple/captureAndArgumentIncompatibleTypes.kt new file mode 100644 index 00000000000..fbd4acddb6e --- /dev/null +++ b/compiler/testData/codegen/boxInline/simple/captureAndArgumentIncompatibleTypes.kt @@ -0,0 +1,13 @@ +// FILE: 1.kt +package test + +inline fun foo(i: Int) = i.toFloat() + +// FILE: 2.kt +import test.* + +fun box(): String { + val captured = 1.0f + val result = 1.let { captured + foo(it) } + return if (result == 2.0f) "OK" else "Fail: $result" +} diff --git a/compiler/testData/codegen/bytecodeText/boxingOptimization/unsignedRangeIteratorSpecialization.kt b/compiler/testData/codegen/bytecodeText/boxingOptimization/unsignedRangeIteratorSpecialization.kt index 6574db06c63..6723d93e3c3 100644 --- a/compiler/testData/codegen/bytecodeText/boxingOptimization/unsignedRangeIteratorSpecialization.kt +++ b/compiler/testData/codegen/bytecodeText/boxingOptimization/unsignedRangeIteratorSpecialization.kt @@ -1,5 +1,4 @@ // WITH_RUNTIME -// IGNORE_BACKEND: JVM_IR fun testUIntRangeForEach() { var s = 0 diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index b8ac448f4f2..d8434cf1839 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -3017,6 +3017,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/simple"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("captureAndArgumentIncompatibleTypes.kt") + public void testCaptureAndArgumentIncompatibleTypes() throws Exception { + runTest("compiler/testData/codegen/boxInline/simple/captureAndArgumentIncompatibleTypes.kt"); + } + @TestMetadata("classObject.kt") public void testClassObject() throws Exception { runTest("compiler/testData/codegen/boxInline/simple/classObject.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 33687e76b36..748ba3f08aa 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3017,6 +3017,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/simple"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); } + @TestMetadata("captureAndArgumentIncompatibleTypes.kt") + public void testCaptureAndArgumentIncompatibleTypes() throws Exception { + runTest("compiler/testData/codegen/boxInline/simple/captureAndArgumentIncompatibleTypes.kt"); + } + @TestMetadata("classObject.kt") public void testClassObject() throws Exception { runTest("compiler/testData/codegen/boxInline/simple/classObject.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index c01d81a29a3..ec15a27e40c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -3017,6 +3017,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/simple"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("captureAndArgumentIncompatibleTypes.kt") + public void testCaptureAndArgumentIncompatibleTypes() throws Exception { + runTest("compiler/testData/codegen/boxInline/simple/captureAndArgumentIncompatibleTypes.kt"); + } + @TestMetadata("classObject.kt") public void testClassObject() throws Exception { runTest("compiler/testData/codegen/boxInline/simple/classObject.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index 26951f6b541..72a0b5d95fb 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3017,6 +3017,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/simple"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); } + @TestMetadata("captureAndArgumentIncompatibleTypes.kt") + public void testCaptureAndArgumentIncompatibleTypes() throws Exception { + runTest("compiler/testData/codegen/boxInline/simple/captureAndArgumentIncompatibleTypes.kt"); + } + @TestMetadata("classObject.kt") public void testClassObject() throws Exception { runTest("compiler/testData/codegen/boxInline/simple/classObject.kt");