Skip inline lambdas in 'InlineCallSite' parameter calculation; Fix for KT-10679: Wrong outer after inline

#KT-10679 Fixed
This commit is contained in:
Michael Bogdanov
2016-01-15 15:13:47 +03:00
parent abf4a5cf43
commit 7eec1d8e1d
9 changed files with 130 additions and 6 deletions
@@ -23,10 +23,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.CodegenUtil;
import org.jetbrains.kotlin.codegen.*;
import org.jetbrains.kotlin.codegen.context.CodegenContext;
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
import org.jetbrains.kotlin.codegen.context.MethodContext;
import org.jetbrains.kotlin.codegen.context.PackageContext;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
@@ -307,8 +304,17 @@ public class InlineCodegen extends CallGenerator {
}
private InlineCallSiteInfo getInlineCallSiteInfo() {
MemberCodegen<?> parentCodegen = codegen.getParentCodegen();
MethodContext context = codegen.getContext();
MemberCodegen<?> parentCodegen = codegen.getParentCodegen();
while (context instanceof InlineLambdaContext) {
CodegenContext closureContext = context.getParentContext();
assert closureContext instanceof ClosureContext : "Parent context of inline lambda should be closure context";
assert closureContext.getParentContext() instanceof MethodContext : "Closure context should appear in method context";
context = (MethodContext) closureContext.getParentContext();
assert parentCodegen instanceof FakeMemberCodegen : "Parent codegen of inlined lambda should be FakeMemberCodegen";
parentCodegen = ((FakeMemberCodegen) parentCodegen).delegate;
}
JvmMethodSignature signature = typeMapper.mapSignature(context.getFunctionDescriptor(), context.getContextKind());
return new InlineCallSiteInfo(parentCodegen.getClassName(), signature.getAsmMethod().getName(), signature.getAsmMethod().getDescriptor());
}
@@ -389,7 +395,7 @@ public class InlineCodegen extends CallGenerator {
private static class FakeMemberCodegen extends MemberCodegen {
private final MemberCodegen delegate;
@NotNull final MemberCodegen delegate;
@NotNull private final String className;
public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull KtElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) {
@@ -0,0 +1,15 @@
import test.*
fun box(): String {
val res = call {
{ "OK" }
}
var enclosingMethod = res.javaClass.enclosingMethod
if (enclosingMethod?.name != "box") return "fail 1: ${enclosingMethod?.name}"
var enclosingClass = res.javaClass.enclosingClass
if (enclosingClass?.name != "AnonymousInLambda_1Kt") return "fail 2: ${enclosingClass?.name}"
return res()
}
@@ -0,0 +1,3 @@
package test
inline fun <R> call(s: () -> R) = s()
@@ -0,0 +1,27 @@
import test.*
fun box(): String {
val res = call {
test { "OK" }
}
var enclosingMethod = res.javaClass.enclosingMethod
if (enclosingMethod?.name != "box") return "fail 1: ${enclosingMethod?.name}"
var enclosingClass = res.javaClass.enclosingClass
if (enclosingClass?.name != "InlineChain_1Kt") return "fail 2: ${enclosingClass?.name}"
val res2 = call {
call {
test { "OK" }
}
}
enclosingMethod = res2.javaClass.enclosingMethod
if (enclosingMethod?.name != "box") return "fail 1: ${enclosingMethod?.name}"
enclosingClass = res2.javaClass.enclosingClass
if (enclosingClass?.name != "InlineChain_1Kt") return "fail 2: ${enclosingClass?.name}"
return res2()
}
@@ -0,0 +1,5 @@
package test
inline fun <R> call(s: () -> R) = s()
inline fun test(crossinline z: () -> String) = { z() }
@@ -0,0 +1,27 @@
import test.*
fun box(): String {
val res = call {
test { "OK" }
}
var enclosingMethod = res.javaClass.enclosingMethod
if (enclosingMethod?.name != "invoke") return "fail 1: ${enclosingMethod?.name}"
var enclosingClass = res.javaClass.enclosingClass
if (enclosingClass?.name != "InlineChain2_1Kt\$box$\$inlined\$call$1") return "fail 2: ${enclosingClass?.name}"
val res2 = call {
call {
test { "OK" }
}
}
enclosingMethod = res2.javaClass.enclosingMethod
if (enclosingMethod?.name != "invoke") return "fail 1: ${enclosingMethod?.name}"
enclosingClass = res2.javaClass.enclosingClass
if (enclosingClass?.name != "InlineChain2_1Kt\$box$\$inlined\$call\$lambda\$lambda$2") return "fail 2: ${enclosingClass?.name}"
return res2()
}
@@ -0,0 +1,5 @@
package test
inline fun <R> call(crossinline s: () -> R) = { s() }()
inline fun test(crossinline z: () -> String) = { z() }
@@ -595,6 +595,24 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/enclosingInfo"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("anonymousInLambda.1.kt")
public void testAnonymousInLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("inlineChain.1.kt")
public void testInlineChain() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("inlineChain2.1.kt")
public void testInlineChain2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("objectInInlineFun.1.kt")
public void testObjectInInlineFun() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/objectInInlineFun.1.kt");
@@ -595,6 +595,24 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/enclosingInfo"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("anonymousInLambda.1.kt")
public void testAnonymousInLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("inlineChain.1.kt")
public void testInlineChain() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("inlineChain2.1.kt")
public void testInlineChain2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("objectInInlineFun.1.kt")
public void testObjectInInlineFun() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/objectInInlineFun.1.kt");