From 23698f93e09b57fc72414c116786987f6651e7ea Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Tue, 7 Mar 2017 12:29:00 +0100 Subject: [PATCH] Fix reification for crossinline lambdas inlined into object literal Inline lambda could capture reified parameter of containing inline function ('a' function) when it is inlined in another one. If it's inlined in any anonymous object we should track it and add reification marker to such anonymous object instance creation to rewrite it on inlining bytecode of 'a' function. #KT-15997 Fixed --- .../kotlin/codegen/inline/MethodInliner.java | 6 ++++ .../codegen/inline/ReifiedTypeInliner.kt | 2 +- .../codegen/boxInline/reified/kt15997.kt | 27 ++++++++++++++ .../codegen/boxInline/reified/kt15997_2.kt | 36 +++++++++++++++++++ .../BlackBoxInlineCodegenTestGenerated.java | 12 +++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 12 +++++++ 6 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/boxInline/reified/kt15997.kt create mode 100644 compiler/testData/codegen/boxInline/reified/kt15997_2.kt 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 b98ed78688c..5f0a9a9cda4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.java @@ -252,6 +252,7 @@ public class MethodInliner { //TODO add skipped this and receiver InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info, invokeCall.finallyDepthShift); result.mergeWithNotChangeInfo(lambdaResult); + result.getReifiedTypeParametersUsages().mergeAll(lambdaResult.getReifiedTypeParametersUsages()); //return value boxing/unboxing Method bridge = typeMapper.mapAsmMethod(ClosureCodegen.getErasedInvokeFunction(info.getFunctionDescriptor())); @@ -486,6 +487,11 @@ public class MethodInliner { ); awaitClassReification = false; } + else if (inliningContext.isInliningLambda && ReifiedTypeInliner.Companion.isOperationReifiedMarker(cur)) { + ReificationArgument reificationArgument = ReifiedTypeInlinerKt.getReificationArgument((MethodInsnNode) cur); + String parameterName = reificationArgument.getParameterName(); + result.getReifiedTypeParametersUsages().addUsedReifiedParameter(parameterName); + } } else if (cur.getOpcode() == Opcodes.GETSTATIC) { FieldInsnNode fieldInsnNode = (FieldInsnNode) cur; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index eeb1a1f5e47..82e5d6febd5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -247,7 +247,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?) } } -private val MethodInsnNode.reificationArgument: ReificationArgument? +val MethodInsnNode.reificationArgument: ReificationArgument? get() { val prev = previous!! diff --git a/compiler/testData/codegen/boxInline/reified/kt15997.kt b/compiler/testData/codegen/boxInline/reified/kt15997.kt new file mode 100644 index 00000000000..ec3b3ce6ec6 --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/kt15997.kt @@ -0,0 +1,27 @@ +// FILE: 1.kt +// FULL_JDK +// WITH_REFLECT +package test + +import kotlin.properties.Delegates +import kotlin.properties.ReadWriteProperty + +var result = "fail" + +inline fun crashMe(): ReadWriteProperty { + return Delegates.observable(Unit, { a, b, c -> result = T::class.java.simpleName }) +} + + +// FILE: 2.kt +import test.* + + +class OK { + var value by crashMe() +} + +fun box(): String { + OK().value = Unit + return result +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/reified/kt15997_2.kt b/compiler/testData/codegen/boxInline/reified/kt15997_2.kt new file mode 100644 index 00000000000..e953b847f29 --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/kt15997_2.kt @@ -0,0 +1,36 @@ +// FILE: 1.kt +// FULL_JDK +// WITH_REFLECT +package test + +import kotlin.properties.Delegates +import kotlin.properties.ReadWriteProperty +import kotlin.properties.ObservableProperty +import kotlin.reflect.KProperty + +var result = "fail" + +public inline fun myObservable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit): + ReadWriteProperty = object : ObservableProperty(initialValue) { + override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue) +} + + +//samely named reified parameter (T) as in myObservable +inline fun crashMe(): ReadWriteProperty { + return myObservable(Unit, { a, b, c -> result = T::class.java.simpleName }) +} + + +// FILE: 2.kt +import test.* + + +class OK { + var value by crashMe() +} + +fun box(): String { + OK().value = Unit + return result +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 6ef76ae1428..6ee9482e420 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -1886,6 +1886,18 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo doTest(fileName); } + @TestMetadata("kt15997.kt") + public void testKt15997() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt15997.kt"); + doTest(fileName); + } + + @TestMetadata("kt15997_2.kt") + public void testKt15997_2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt15997_2.kt"); + doTest(fileName); + } + @TestMetadata("kt6988.kt") public void testKt6988() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt6988.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 33ece1745e6..38b9b34699a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -1886,6 +1886,18 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi doTest(fileName); } + @TestMetadata("kt15997.kt") + public void testKt15997() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt15997.kt"); + doTest(fileName); + } + + @TestMetadata("kt15997_2.kt") + public void testKt15997_2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt15997_2.kt"); + doTest(fileName); + } + @TestMetadata("kt6988.kt") public void testKt6988() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/kt6988.kt");