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 0bfecb09e7e..5f5586cdbed 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.java @@ -522,7 +522,7 @@ public class InlineCodegen extends CallGenerator { private void generateClosuresBodies() { for (LambdaInfo info : expressionMap.values()) { - info.generateLambdaBody(codegen); + info.generateLambdaBody(codegen, reifiedTypeInliner); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt index 2b42076990d..33766a92562 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -50,7 +50,7 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean, @JvmField val is lateinit var node: SMAPAndMethodNode - abstract fun generateLambdaBody(codegen: ExpressionCodegen) + abstract fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) fun addAllParameters(remapper: FieldRemapper): Parameters { val builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, invokeMethod.descriptor, this) @@ -81,7 +81,8 @@ class DefaultLambda( override val lambdaClassType: Type, val capturedArgs: Array, val parameterDescriptor: ValueParameterDescriptor, - val offset: Int + val offset: Int, + val needReification: Boolean ) : LambdaInfo(parameterDescriptor.isCrossinline, false) { val parameterOffsetsInDefault: MutableList = arrayListOf() @@ -99,7 +100,7 @@ class DefaultLambda( override fun isMyLabel(name: String): Boolean = false - override fun generateLambdaBody(codegen: ExpressionCodegen) { + override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) { val classReader = InlineCodegenUtil.buildClassReaderByInternalName(codegen.state, lambdaClassType.internalName) val descriptor = Type.getMethodDescriptor(Type.VOID_TYPE, *capturedArgs) @@ -129,6 +130,11 @@ class DefaultLambda( invokeMethod.name, invokeMethod.descriptor, lambdaClassType.internalName)!! + + if (needReification) { + //nested classes could also require reification + reifiedTypeInliner.reifyInstructions(node.node) + } } } @@ -223,7 +229,7 @@ class ExpressionLambda( val isPropertyReference: Boolean get() = propertyReferenceInfo != null - override fun generateLambdaBody(codegen: ExpressionCodegen) { + override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) { val closureContext = if (isPropertyReference) codegen.getContext().intoAnonymousClass(classDescriptor, codegen, OwnerKind.IMPLEMENTATION) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/defaultMethodUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/defaultMethodUtil.kt index ba9bbd9c47e..90dc02ad5b1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/defaultMethodUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/defaultMethodUtil.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.OwnerKind import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.DEFAULT_LAMBDA_FAKE_CALL import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getConstant +import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.Companion.isNeedClassReificationMarker import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence import org.jetbrains.kotlin.codegen.optimization.common.asSequence import org.jetbrains.kotlin.codegen.optimization.common.insnText @@ -153,7 +154,7 @@ private fun extractDefaultLambdasInfo( instanceInstuction = instanceInstuction.previous } - val (owner, argTypes) = when (instanceInstuction) { + val (owner, argTypes, needReification) = when (instanceInstuction) { is MethodInsnNode -> { assert(instanceInstuction.name == "") { "Expected constructor call for default lambda, but $instanceInstuction" } val ownerInternalName = instanceInstuction.owner @@ -170,20 +171,23 @@ private fun extractDefaultLambdasInfo( addAll(InsnSequence(instanceInstuction, varAssignmentInstruction.next).toList()) } - Type.getObjectType(instanceInstuction.owner) to Type.getArgumentTypes(instanceInstuction.desc) + val needReification = instanceCreation.previous.takeIf { isNeedClassReificationMarker(it) }?.let { toDelete.add(it) } != null + Triple(Type.getObjectType(instanceInstuction.owner), Type.getArgumentTypes(instanceInstuction.desc), needReification) } is FieldInsnNode -> { toDelete.addAll(InsnSequence(instanceInstuction, varAssignmentInstruction.next).toList()) - Type.getObjectType(instanceInstuction.owner) to emptyArray() + val needReification = instanceInstuction.previous.takeIf { isNeedClassReificationMarker(it) }?.let { toDelete.add(it) } != null + + Triple(Type.getObjectType(instanceInstuction.owner), emptyArray(), needReification) } else -> throw RuntimeException("Can't extract default lambda info $it.\n Unknown instruction: ${instanceInstuction.insnText}") } toInsert.add(varAssignmentInstruction to defaultLambdaFakeCallStub(argTypes, it.varIndex)) - DefaultLambda(owner, argTypes, defaultLambdas[it.varIndex]!!, it.varIndex) + DefaultLambda(owner, argTypes, defaultLambdas[it.varIndex]!!, it.varIndex, needReification) } } diff --git a/compiler/testData/codegen/boxInline/reified/defaultLambda/chain.kt b/compiler/testData/codegen/boxInline/reified/defaultLambda/chain.kt new file mode 100644 index 00000000000..a9f86a594cd --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/defaultLambda/chain.kt @@ -0,0 +1,26 @@ +// FILE: 1.kt +// SKIP_INLINE_CHECK_IN: inlineFun$default +//WITH_RUNTIME +package test + +class OK +class FAIL + +@Suppress("NOT_YET_SUPPORTED_IN_INLINE") +inline fun inlineFun(lambda: () -> String = { T::class.java.simpleName }): String { + return lambda() +} + +inline fun inlineFun2(): String { + return inlineFun() +} + +// FILE: 2.kt + +import test.* + + + +fun box(): String { + return inlineFun2() +} diff --git a/compiler/testData/codegen/boxInline/reified/defaultLambda/nested.kt b/compiler/testData/codegen/boxInline/reified/defaultLambda/nested.kt new file mode 100644 index 00000000000..26e073fb5bd --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/defaultLambda/nested.kt @@ -0,0 +1,19 @@ +// FILE: 1.kt +// SKIP_INLINE_CHECK_IN: inlineFun$default +//WITH_RUNTIME +package test + +@Suppress("NOT_YET_SUPPORTED_IN_INLINE") +inline fun inlineFun(p: String, lambda: () -> String = { { p + T::class.java.simpleName } () }): String { + return lambda() +} + +// FILE: 2.kt + +import test.* + +class K + +fun box(): String { + return inlineFun("O") +} diff --git a/compiler/testData/codegen/boxInline/reified/defaultLambda/nested2.kt b/compiler/testData/codegen/boxInline/reified/defaultLambda/nested2.kt new file mode 100644 index 00000000000..eb9ae8bafaa --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/defaultLambda/nested2.kt @@ -0,0 +1,21 @@ +// FILE: 1.kt +// SKIP_INLINE_CHECK_IN: inlineFun$default +//WITH_RUNTIME +package test + +@Suppress("NOT_YET_SUPPORTED_IN_INLINE") +inline fun inlineFun(p: String, crossinline lambda: () -> String = { { p + T::class.java.simpleName } () }): String { + return { + lambda() + } () +} + +// FILE: 2.kt + +import test.* + +class OK + +fun box(): String { + return inlineFun() +} diff --git a/compiler/testData/codegen/boxInline/reified/defaultLambda/nested2Static.kt b/compiler/testData/codegen/boxInline/reified/defaultLambda/nested2Static.kt new file mode 100644 index 00000000000..e02a5b13f39 --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/defaultLambda/nested2Static.kt @@ -0,0 +1,21 @@ +// FILE: 1.kt +// SKIP_INLINE_CHECK_IN: inlineFun$default +//WITH_RUNTIME +package test + +@Suppress("NOT_YET_SUPPORTED_IN_INLINE") +inline fun inlineFun(crossinline lambda: () -> String = { { T::class.java.simpleName } () }): String { + return { + lambda() + } () +} + +// FILE: 2.kt + +import test.* + +class OK + +fun box(): String { + return inlineFun() +} diff --git a/compiler/testData/codegen/boxInline/reified/defaultLambda/nestedStatic.kt b/compiler/testData/codegen/boxInline/reified/defaultLambda/nestedStatic.kt new file mode 100644 index 00000000000..cac8b2b977f --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/defaultLambda/nestedStatic.kt @@ -0,0 +1,19 @@ +// FILE: 1.kt +// SKIP_INLINE_CHECK_IN: inlineFun$default +//WITH_RUNTIME +package test + +@Suppress("NOT_YET_SUPPORTED_IN_INLINE") +inline fun inlineFun(lambda: () -> String = { { T::class.java.simpleName } () }): String { + return lambda() +} + +// FILE: 2.kt + +import test.* + +class OK + +fun box(): String { + return inlineFun() +} diff --git a/compiler/testData/codegen/boxInline/reified/defaultLambda/simple.kt b/compiler/testData/codegen/boxInline/reified/defaultLambda/simple.kt new file mode 100644 index 00000000000..eaa43de838f --- /dev/null +++ b/compiler/testData/codegen/boxInline/reified/defaultLambda/simple.kt @@ -0,0 +1,19 @@ +// FILE: 1.kt +// SKIP_INLINE_CHECK_IN: inlineFun$default +//WITH_RUNTIME +package test + +@Suppress("NOT_YET_SUPPORTED_IN_INLINE") +inline fun inlineFun(lambda: () -> String = { T::class.java.simpleName }): String { + return lambda() +} + +// FILE: 2.kt + +import test.* + +class OK + +fun box(): String { + return inlineFun() +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 796320348c9..f9ea22b97c0 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -2141,6 +2141,51 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo } } + @TestMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DefaultLambda extends AbstractBlackBoxInlineCodegenTest { + public void testAllFilesPresentInDefaultLambda() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified/defaultLambda"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("chain.kt") + public void testChain() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/chain.kt"); + doTest(fileName); + } + + @TestMetadata("nested.kt") + public void testNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested.kt"); + doTest(fileName); + } + + @TestMetadata("nested2.kt") + public void testNested2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested2.kt"); + doTest(fileName); + } + + @TestMetadata("nested2Static.kt") + public void testNested2Static() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested2Static.kt"); + doTest(fileName); + } + + @TestMetadata("nestedStatic.kt") + public void testNestedStatic() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nestedStatic.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/simple.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/reified/isCheck") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 8ce1230eef7..c397dceb089 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -2141,6 +2141,51 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi } } + @TestMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class DefaultLambda extends AbstractCompileKotlinAgainstInlineKotlinTest { + public void testAllFilesPresentInDefaultLambda() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified/defaultLambda"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("chain.kt") + public void testChain() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/chain.kt"); + doTest(fileName); + } + + @TestMetadata("nested.kt") + public void testNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested.kt"); + doTest(fileName); + } + + @TestMetadata("nested2.kt") + public void testNested2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested2.kt"); + doTest(fileName); + } + + @TestMetadata("nested2Static.kt") + public void testNested2Static() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nested2Static.kt"); + doTest(fileName); + } + + @TestMetadata("nestedStatic.kt") + public void testNestedStatic() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/nestedStatic.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/defaultLambda/simple.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/reified/isCheck") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)