Fix for KT-10137: Internal error: couldn't inline method call on lambda taking extension function parameter

#KT-10137 Fixed
This commit is contained in:
Michael Bogdanov
2015-11-24 12:46:04 +03:00
parent a19bdaeb23
commit 3da463be27
10 changed files with 129 additions and 3 deletions
@@ -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);
}
}
@@ -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);
@@ -0,0 +1,10 @@
import test.*
fun box(): String {
var result = "fail"
W("OK").safe {
result = this as String
}
return result
}
@@ -0,0 +1,10 @@
package test
class W(val value: Any)
inline fun W.safe(crossinline body : Any.() -> Unit) {
{
this.value?.body()
}()
}
@@ -0,0 +1,12 @@
import test.*
fun box(): String {
var result = "fail"
W("OK").safe {
{
result = this as String
}()
}
return result
}
@@ -0,0 +1,10 @@
package test
class W(val value: Any)
inline fun W.safe(crossinline body : Any.() -> Unit) {
{
this.value?.body()
}()
}
@@ -0,0 +1,10 @@
import test.*
fun box(): String {
var result = "fail"
W("OK").safe {
result = this as String
}
return result
}
@@ -0,0 +1,8 @@
package test
class W(val value: Any)
inline fun W.safe(body : Any.() -> Unit) {
this.value?.body()
}
@@ -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");
@@ -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");