Skip to content

Commit 7eec1d8

Browse files
author
Michael Bogdanov
committed
Skip inline lambdas in 'InlineCallSite' parameter calculation; Fix for KT-10679: Wrong outer after inline
#KT-10679 Fixed
1 parent abf4a5c commit 7eec1d8

File tree

9 files changed

+130
-6
lines changed

9 files changed

+130
-6
lines changed

compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323
import org.jetbrains.annotations.Nullable;
2424
import org.jetbrains.kotlin.backend.common.CodegenUtil;
2525
import org.jetbrains.kotlin.codegen.*;
26-
import org.jetbrains.kotlin.codegen.context.CodegenContext;
27-
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
28-
import org.jetbrains.kotlin.codegen.context.MethodContext;
29-
import org.jetbrains.kotlin.codegen.context.PackageContext;
26+
import org.jetbrains.kotlin.codegen.context.*;
3027
import org.jetbrains.kotlin.codegen.state.GenerationState;
3128
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
3229
import org.jetbrains.kotlin.descriptors.*;
@@ -307,8 +304,17 @@ public boolean isMyLabel(@NotNull String name) {
307304
}
308305

309306
private InlineCallSiteInfo getInlineCallSiteInfo() {
310-
MemberCodegen<?> parentCodegen = codegen.getParentCodegen();
311307
MethodContext context = codegen.getContext();
308+
MemberCodegen<?> parentCodegen = codegen.getParentCodegen();
309+
while (context instanceof InlineLambdaContext) {
310+
CodegenContext closureContext = context.getParentContext();
311+
assert closureContext instanceof ClosureContext : "Parent context of inline lambda should be closure context";
312+
assert closureContext.getParentContext() instanceof MethodContext : "Closure context should appear in method context";
313+
context = (MethodContext) closureContext.getParentContext();
314+
assert parentCodegen instanceof FakeMemberCodegen : "Parent codegen of inlined lambda should be FakeMemberCodegen";
315+
parentCodegen = ((FakeMemberCodegen) parentCodegen).delegate;
316+
}
317+
312318
JvmMethodSignature signature = typeMapper.mapSignature(context.getFunctionDescriptor(), context.getContextKind());
313319
return new InlineCallSiteInfo(parentCodegen.getClassName(), signature.getAsmMethod().getName(), signature.getAsmMethod().getDescriptor());
314320
}
@@ -389,7 +395,7 @@ private static SMAP createSMAPWithDefaultMapping(
389395

390396
private static class FakeMemberCodegen extends MemberCodegen {
391397

392-
private final MemberCodegen delegate;
398+
@NotNull final MemberCodegen delegate;
393399
@NotNull private final String className;
394400

395401
public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull KtElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import test.*
2+
3+
fun box(): String {
4+
val res = call {
5+
{ "OK" }
6+
}
7+
8+
var enclosingMethod = res.javaClass.enclosingMethod
9+
if (enclosingMethod?.name != "box") return "fail 1: ${enclosingMethod?.name}"
10+
11+
var enclosingClass = res.javaClass.enclosingClass
12+
if (enclosingClass?.name != "AnonymousInLambda_1Kt") return "fail 2: ${enclosingClass?.name}"
13+
14+
return res()
15+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package test
2+
3+
inline fun <R> call(s: () -> R) = s()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import test.*
2+
3+
fun box(): String {
4+
val res = call {
5+
test { "OK" }
6+
}
7+
8+
var enclosingMethod = res.javaClass.enclosingMethod
9+
if (enclosingMethod?.name != "box") return "fail 1: ${enclosingMethod?.name}"
10+
11+
var enclosingClass = res.javaClass.enclosingClass
12+
if (enclosingClass?.name != "InlineChain_1Kt") return "fail 2: ${enclosingClass?.name}"
13+
14+
val res2 = call {
15+
call {
16+
test { "OK" }
17+
}
18+
}
19+
20+
enclosingMethod = res2.javaClass.enclosingMethod
21+
if (enclosingMethod?.name != "box") return "fail 1: ${enclosingMethod?.name}"
22+
23+
enclosingClass = res2.javaClass.enclosingClass
24+
if (enclosingClass?.name != "InlineChain_1Kt") return "fail 2: ${enclosingClass?.name}"
25+
26+
return res2()
27+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package test
2+
3+
inline fun <R> call(s: () -> R) = s()
4+
5+
inline fun test(crossinline z: () -> String) = { z() }
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import test.*
2+
3+
fun box(): String {
4+
val res = call {
5+
test { "OK" }
6+
}
7+
8+
var enclosingMethod = res.javaClass.enclosingMethod
9+
if (enclosingMethod?.name != "invoke") return "fail 1: ${enclosingMethod?.name}"
10+
11+
var enclosingClass = res.javaClass.enclosingClass
12+
if (enclosingClass?.name != "InlineChain2_1Kt\$box$\$inlined\$call$1") return "fail 2: ${enclosingClass?.name}"
13+
14+
val res2 = call {
15+
call {
16+
test { "OK" }
17+
}
18+
}
19+
20+
enclosingMethod = res2.javaClass.enclosingMethod
21+
if (enclosingMethod?.name != "invoke") return "fail 1: ${enclosingMethod?.name}"
22+
23+
enclosingClass = res2.javaClass.enclosingClass
24+
if (enclosingClass?.name != "InlineChain2_1Kt\$box$\$inlined\$call\$lambda\$lambda$2") return "fail 2: ${enclosingClass?.name}"
25+
26+
return res2()
27+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package test
2+
3+
inline fun <R> call(crossinline s: () -> R) = { s() }()
4+
5+
inline fun test(crossinline z: () -> String) = { z() }

compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxInlineCodegenTestGenerated.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,24 @@ public void testAllFilesPresentInEnclosingInfo() throws Exception {
595595
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/enclosingInfo"), Pattern.compile("^(.+)\\.1.kt$"), true);
596596
}
597597

598+
@TestMetadata("anonymousInLambda.1.kt")
599+
public void testAnonymousInLambda() throws Exception {
600+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.1.kt");
601+
doTestMultiFileWithInlineCheck(fileName);
602+
}
603+
604+
@TestMetadata("inlineChain.1.kt")
605+
public void testInlineChain() throws Exception {
606+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.1.kt");
607+
doTestMultiFileWithInlineCheck(fileName);
608+
}
609+
610+
@TestMetadata("inlineChain2.1.kt")
611+
public void testInlineChain2() throws Exception {
612+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.1.kt");
613+
doTestMultiFileWithInlineCheck(fileName);
614+
}
615+
598616
@TestMetadata("objectInInlineFun.1.kt")
599617
public void testObjectInInlineFun() throws Exception {
600618
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/objectInInlineFun.1.kt");

compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,24 @@ public void testAllFilesPresentInEnclosingInfo() throws Exception {
595595
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/enclosingInfo"), Pattern.compile("^(.+)\\.1.kt$"), true);
596596
}
597597

598+
@TestMetadata("anonymousInLambda.1.kt")
599+
public void testAnonymousInLambda() throws Exception {
600+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.1.kt");
601+
doBoxTestWithInlineCheck(fileName);
602+
}
603+
604+
@TestMetadata("inlineChain.1.kt")
605+
public void testInlineChain() throws Exception {
606+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain.1.kt");
607+
doBoxTestWithInlineCheck(fileName);
608+
}
609+
610+
@TestMetadata("inlineChain2.1.kt")
611+
public void testInlineChain2() throws Exception {
612+
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/inlineChain2.1.kt");
613+
doBoxTestWithInlineCheck(fileName);
614+
}
615+
598616
@TestMetadata("objectInInlineFun.1.kt")
599617
public void testObjectInInlineFun() throws Exception {
600618
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/enclosingInfo/objectInInlineFun.1.kt");

0 commit comments

Comments
 (0)