From 7eec1d8e1da0cf62c81467d42c1897fb6836e193 Mon Sep 17 00:00:00 2001 From: Michael Bogdanov Date: Fri, 15 Jan 2016 15:13:47 +0300 Subject: [PATCH] Skip inline lambdas in 'InlineCallSite' parameter calculation; Fix for KT-10679: Wrong outer after inline #KT-10679 Fixed --- .../kotlin/codegen/inline/InlineCodegen.java | 18 ++++++++----- .../enclosingInfo/anonymousInLambda.1.kt | 15 +++++++++++ .../enclosingInfo/anonymousInLambda.2.kt | 3 +++ .../boxInline/enclosingInfo/inlineChain.1.kt | 27 +++++++++++++++++++ .../boxInline/enclosingInfo/inlineChain.2.kt | 5 ++++ .../boxInline/enclosingInfo/inlineChain2.1.kt | 27 +++++++++++++++++++ .../boxInline/enclosingInfo/inlineChain2.2.kt | 5 ++++ .../BlackBoxInlineCodegenTestGenerated.java | 18 +++++++++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 18 +++++++++++++ 9 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.1.kt create mode 100644 compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.2.kt create mode 100644 compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.1.kt create mode 100644 compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.2.kt create mode 100644 compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.1.kt create mode 100644 compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.2.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java index bd0514f5c00..2c7971b35e3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -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) { diff --git a/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.1.kt b/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.1.kt new file mode 100644 index 00000000000..c6d34486426 --- /dev/null +++ b/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.1.kt @@ -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() +} diff --git a/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.2.kt b/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.2.kt new file mode 100644 index 00000000000..24493b57a7a --- /dev/null +++ b/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.2.kt @@ -0,0 +1,3 @@ +package test + +inline fun call(s: () -> R) = s() diff --git a/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.1.kt b/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.1.kt new file mode 100644 index 00000000000..68f78b9daad --- /dev/null +++ b/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.1.kt @@ -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() +} diff --git a/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.2.kt b/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.2.kt new file mode 100644 index 00000000000..3a1cc9ee511 --- /dev/null +++ b/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.2.kt @@ -0,0 +1,5 @@ +package test + +inline fun call(s: () -> R) = s() + +inline fun test(crossinline z: () -> String) = { z() } diff --git a/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.1.kt b/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.1.kt new file mode 100644 index 00000000000..ce1cac4ac7c --- /dev/null +++ b/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.1.kt @@ -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() +} diff --git a/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.2.kt b/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.2.kt new file mode 100644 index 00000000000..d695be1d81a --- /dev/null +++ b/compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.2.kt @@ -0,0 +1,5 @@ +package test + +inline fun call(crossinline s: () -> R) = { s() }() + +inline fun test(crossinline z: () -> String) = { z() } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 12f839c5ada..3f5fb158684 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index feee11a8559..51fdbced475 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -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");