From 3da463be272a2f9f2211691412924dc7573830e5 Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Tue, 24 Nov 2015 12:46:04 +0300 Subject: [PATCH] Fix for KT-10137: Internal error: couldn't inline method call on lambda taking extension function parameter #KT-10137 Fixed --- .../codegen/inline/InlineCodegenUtil.java | 19 +++++++++++++++++++ .../kotlin/codegen/inline/MethodInliner.java | 17 ++++++++++++++--- .../boxInline/anonymousObject/safeCall.1.kt | 10 ++++++++++ .../boxInline/anonymousObject/safeCall.2.kt | 10 ++++++++++ .../boxInline/anonymousObject/safeCall_2.1.kt | 12 ++++++++++++ .../boxInline/anonymousObject/safeCall_2.2.kt | 10 ++++++++++ .../codegen/boxInline/simple/safeCall.1.kt | 10 ++++++++++ .../codegen/boxInline/simple/safeCall.2.kt | 8 ++++++++ .../BlackBoxInlineCodegenTestGenerated.java | 18 ++++++++++++++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 18 ++++++++++++++++++ 10 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/anonymousObject/safeCall.1.kt create mode 100644 compiler/testData/codegen/boxInline/anonymousObject/safeCall.2.kt create mode 100644 compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.1.kt create mode 100644 compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.2.kt create mode 100644 compiler/testData/codegen/boxInline/simple/safeCall.1.kt create mode 100644 compiler/testData/codegen/boxInline/simple/safeCall.2.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java index b34e5f7a2ad..ce793699dae 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenUtil.java @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.CodegenContext; import org.jetbrains.kotlin.codegen.context.CodegenContextUtil; import org.jetbrains.kotlin.codegen.context.MethodContext; +import org.jetbrains.kotlin.codegen.optimization.common.UtilKt; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.JetTypeMapper; import org.jetbrains.kotlin.descriptors.*; @@ -492,4 +493,22 @@ public class InlineCodegenUtil { public static boolean isThis0(String name) { return THIS$0.equals(name); } + + @Nullable + public static AbstractInsnNode getPrevMeaningful(@NotNull AbstractInsnNode node) { + AbstractInsnNode result = node.getPrevious(); + while (result != null && !UtilKt.isMeaningful(result)) { + result = result.getPrevious(); + } + return result; + } + + public static void removeInterval(@NotNull MethodNode node, @NotNull AbstractInsnNode startInc, @NotNull AbstractInsnNode endInc) { + while (startInc != endInc) { + AbstractInsnNode next = startInc.getNext(); + node.instructions.remove(startInc); + startInc = next; + } + node.instructions.remove(startInc); + } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java index c2039205d47..e07cc90dd9c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.inline; import com.google.common.collect.Lists; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.codegen.ClosureCodegen; import org.jetbrains.kotlin.codegen.StackValue; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; @@ -440,11 +441,16 @@ public class MethodInliner { if (sourceValue.insns.size() == 1) { AbstractInsnNode insnNode = sourceValue.insns.iterator().next(); + AbstractInsnNode processingInstruction = insnNode; - lambdaInfo = getLambdaIfExists(insnNode); + if (insnNode.getOpcode() == Opcodes.SWAP) { + processingInstruction = InlineCodegenUtil.getPrevMeaningful(insnNode); + } + lambdaInfo = getLambdaIfExists(processingInstruction); if (lambdaInfo != null) { //remove inlinable access - node.instructions.remove(insnNode); + assert processingInstruction != null; + InlineCodegenUtil.removeInterval(node, processingInstruction, insnNode); } } @@ -546,7 +552,12 @@ public class MethodInliner { return inliningContext.typeMapping.containsKey(owner); } - public LambdaInfo getLambdaIfExists(AbstractInsnNode insnNode) { + @Nullable + public LambdaInfo getLambdaIfExists(@Nullable AbstractInsnNode insnNode) { + if (insnNode == null) { + return null; + } + if (insnNode.getOpcode() == Opcodes.ALOAD) { int varIndex = ((VarInsnNode) insnNode).var; return getLambdaIfExists(varIndex); diff --git a/compiler/testData/codegen/boxInline/anonymousObject/safeCall.1.kt b/compiler/testData/codegen/boxInline/anonymousObject/safeCall.1.kt new file mode 100644 index 00000000000..4891862f4ed --- /dev/null +++ b/compiler/testData/codegen/boxInline/anonymousObject/safeCall.1.kt @@ -0,0 +1,10 @@ +import test.* + +fun box(): String { + var result = "fail" + W("OK").safe { + result = this as String + } + + return result +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/anonymousObject/safeCall.2.kt b/compiler/testData/codegen/boxInline/anonymousObject/safeCall.2.kt new file mode 100644 index 00000000000..f30d224303a --- /dev/null +++ b/compiler/testData/codegen/boxInline/anonymousObject/safeCall.2.kt @@ -0,0 +1,10 @@ +package test + +class W(val value: Any) + +inline fun W.safe(crossinline body : Any.() -> Unit) { + { + this.value?.body() + }() +} + diff --git a/compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.1.kt b/compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.1.kt new file mode 100644 index 00000000000..847b9098fa4 --- /dev/null +++ b/compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.1.kt @@ -0,0 +1,12 @@ +import test.* + +fun box(): String { + var result = "fail" + W("OK").safe { + { + result = this as String + }() + } + + return result +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.2.kt b/compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.2.kt new file mode 100644 index 00000000000..f30d224303a --- /dev/null +++ b/compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.2.kt @@ -0,0 +1,10 @@ +package test + +class W(val value: Any) + +inline fun W.safe(crossinline body : Any.() -> Unit) { + { + this.value?.body() + }() +} + diff --git a/compiler/testData/codegen/boxInline/simple/safeCall.1.kt b/compiler/testData/codegen/boxInline/simple/safeCall.1.kt new file mode 100644 index 00000000000..4891862f4ed --- /dev/null +++ b/compiler/testData/codegen/boxInline/simple/safeCall.1.kt @@ -0,0 +1,10 @@ +import test.* + +fun box(): String { + var result = "fail" + W("OK").safe { + result = this as String + } + + return result +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/simple/safeCall.2.kt b/compiler/testData/codegen/boxInline/simple/safeCall.2.kt new file mode 100644 index 00000000000..15e6a219ae3 --- /dev/null +++ b/compiler/testData/codegen/boxInline/simple/safeCall.2.kt @@ -0,0 +1,8 @@ +package test + +class W(val value: Any) + +inline fun W.safe(body : Any.() -> Unit) { + this.value?.body() +} + diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 0f9bdd35d7c..25f8cbd64de 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -151,6 +151,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("safeCall.1.kt") + public void testSafeCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/safeCall.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + + @TestMetadata("safeCall_2.1.kt") + public void testSafeCall_2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/properRecapturing") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -1321,6 +1333,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTestMultiFileWithInlineCheck(fileName); } + @TestMetadata("safeCall.1.kt") + public void testSafeCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/simple/safeCall.1.kt"); + doTestMultiFileWithInlineCheck(fileName); + } + @TestMetadata("severalClosures.1.kt") public void testSeveralClosures() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/simple/severalClosures.1.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 27d43a3f48a..801836785b5 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -151,6 +151,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("safeCall.1.kt") + public void testSafeCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/safeCall.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + + @TestMetadata("safeCall_2.1.kt") + public void testSafeCall_2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/safeCall_2.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/properRecapturing") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -1321,6 +1333,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doBoxTestWithInlineCheck(fileName); } + @TestMetadata("safeCall.1.kt") + public void testSafeCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/simple/safeCall.1.kt"); + doBoxTestWithInlineCheck(fileName); + } + @TestMetadata("severalClosures.1.kt") public void testSeveralClosures() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/simple/severalClosures.1.kt");