diff --git a/compiler/testData/codegen/boxInline/anonymousObject/enumWhen/callSite.kt b/compiler/testData/codegen/boxInline/anonymousObject/enumWhen/callSite.kt index c92261bac4b..3539bbfb478 100644 --- a/compiler/testData/codegen/boxInline/anonymousObject/enumWhen/callSite.kt +++ b/compiler/testData/codegen/boxInline/anonymousObject/enumWhen/callSite.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/anonymousObject/kt8133.kt b/compiler/testData/codegen/boxInline/anonymousObject/kt8133.kt index 62037718820..afbe87298a7 100644 --- a/compiler/testData/codegen/boxInline/anonymousObject/kt8133.kt +++ b/compiler/testData/codegen/boxInline/anonymousObject/kt8133.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/anonymousObject/kt9591.kt b/compiler/testData/codegen/boxInline/anonymousObject/kt9591.kt index 0cc1a4afc20..858e2bd78d1 100644 --- a/compiler/testData/codegen/boxInline/anonymousObject/kt9591.kt +++ b/compiler/testData/codegen/boxInline/anonymousObject/kt9591.kt @@ -1,5 +1,6 @@ -// FILE: 1.kt +// NO_CHECK_LAMBDA_INLINING // WITH_RUNTIME +// FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/anonymousObject/kt9877.kt b/compiler/testData/codegen/boxInline/anonymousObject/kt9877.kt index d3cd3ef82d6..cd05b1f097d 100644 --- a/compiler/testData/codegen/boxInline/anonymousObject/kt9877.kt +++ b/compiler/testData/codegen/boxInline/anonymousObject/kt9877.kt @@ -1,5 +1,6 @@ -// FILE: 1.kt +// NO_CHECK_LAMBDA_INLINING // WITH_RUNTIME +// FILE: 1.kt package test fun T.noInline(p: (T) -> Unit) { diff --git a/compiler/testData/codegen/boxInline/anonymousObject/kt9877_2.kt b/compiler/testData/codegen/boxInline/anonymousObject/kt9877_2.kt index 262c6930193..74159b48cb9 100644 --- a/compiler/testData/codegen/boxInline/anonymousObject/kt9877_2.kt +++ b/compiler/testData/codegen/boxInline/anonymousObject/kt9877_2.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/anonymousObject/properRecapturing/lambdaChain.kt b/compiler/testData/codegen/boxInline/anonymousObject/properRecapturing/lambdaChain.kt index 3dfa283eec8..317e87c1467 100644 --- a/compiler/testData/codegen/boxInline/anonymousObject/properRecapturing/lambdaChain.kt +++ b/compiler/testData/codegen/boxInline/anonymousObject/properRecapturing/lambdaChain.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/argumentOrder/boundFunctionReference.kt b/compiler/testData/codegen/boxInline/argumentOrder/boundFunctionReference.kt index 9d1a88b367f..0607fff5303 100644 --- a/compiler/testData/codegen/boxInline/argumentOrder/boundFunctionReference.kt +++ b/compiler/testData/codegen/boxInline/argumentOrder/boundFunctionReference.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/argumentOrder/boundFunctionReference2.kt b/compiler/testData/codegen/boxInline/argumentOrder/boundFunctionReference2.kt index 3b071487504..afeec54fea1 100644 --- a/compiler/testData/codegen/boxInline/argumentOrder/boundFunctionReference2.kt +++ b/compiler/testData/codegen/boxInline/argumentOrder/boundFunctionReference2.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/argumentOrder/extension.kt b/compiler/testData/codegen/boxInline/argumentOrder/extension.kt index b58a2cfab1e..94fa2176376 100644 --- a/compiler/testData/codegen/boxInline/argumentOrder/extension.kt +++ b/compiler/testData/codegen/boxInline/argumentOrder/extension.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/argumentOrder/extensionInClass.kt b/compiler/testData/codegen/boxInline/argumentOrder/extensionInClass.kt index 8870ba6311a..a6c970d4c36 100644 --- a/compiler/testData/codegen/boxInline/argumentOrder/extensionInClass.kt +++ b/compiler/testData/codegen/boxInline/argumentOrder/extensionInClass.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt // WITH_RUNTIME package test diff --git a/compiler/testData/codegen/boxInline/argumentOrder/lambdaMigration.kt b/compiler/testData/codegen/boxInline/argumentOrder/lambdaMigration.kt index 9f250938e48..71d688725b8 100644 --- a/compiler/testData/codegen/boxInline/argumentOrder/lambdaMigration.kt +++ b/compiler/testData/codegen/boxInline/argumentOrder/lambdaMigration.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/argumentOrder/lambdaMigrationInClass.kt b/compiler/testData/codegen/boxInline/argumentOrder/lambdaMigrationInClass.kt index 638855d7972..e371e456f9f 100644 --- a/compiler/testData/codegen/boxInline/argumentOrder/lambdaMigrationInClass.kt +++ b/compiler/testData/codegen/boxInline/argumentOrder/lambdaMigrationInClass.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/argumentOrder/simple.kt b/compiler/testData/codegen/boxInline/argumentOrder/simple.kt index bc5c17dfb17..e7dd36ac31a 100644 --- a/compiler/testData/codegen/boxInline/argumentOrder/simple.kt +++ b/compiler/testData/codegen/boxInline/argumentOrder/simple.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/argumentOrder/simpleInClass.kt b/compiler/testData/codegen/boxInline/argumentOrder/simpleInClass.kt index bfca5a89979..ae7f9c84f67 100644 --- a/compiler/testData/codegen/boxInline/argumentOrder/simpleInClass.kt +++ b/compiler/testData/codegen/boxInline/argumentOrder/simpleInClass.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/callableReference/intrinsic.kt b/compiler/testData/codegen/boxInline/callableReference/intrinsic.kt index 2be864d9bb9..881b2028bc0 100644 --- a/compiler/testData/codegen/boxInline/callableReference/intrinsic.kt +++ b/compiler/testData/codegen/boxInline/callableReference/intrinsic.kt @@ -2,8 +2,8 @@ package test -inline fun call(p: String, s: String.() -> Int): Int { - return p.s() +inline fun call(a: String, b: String, s: String.(String) -> String): Int { + return a.s(b) } // FILE: 2.kt @@ -11,5 +11,5 @@ inline fun call(p: String, s: String.() -> Int): Int { import test.* fun box() : String { - return if (call("123", String::length) == 3) "OK" else "fail" + return return call("O", "K", String::plus) } diff --git a/compiler/testData/codegen/boxInline/complex/swapAndWith.kt b/compiler/testData/codegen/boxInline/complex/swapAndWith.kt index 2f60307c2c6..0c1f2a7c6ed 100644 --- a/compiler/testData/codegen/boxInline/complex/swapAndWith.kt +++ b/compiler/testData/codegen/boxInline/complex/swapAndWith.kt @@ -1,3 +1,4 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt package test diff --git a/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.kt b/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.kt index 5cb2afecf50..37307ba3cd0 100644 --- a/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.kt +++ b/compiler/testData/codegen/boxInline/enclosingInfo/anonymousInLambda.kt @@ -1,5 +1,6 @@ -// FILE: 1.kt +// NO_CHECK_LAMBDA_INLINING // WITH_REFLECT +// FILE: 1.kt package test inline fun call(s: () -> R) = s() diff --git a/compiler/testData/codegen/boxInline/innerClasses/kt10259.kt b/compiler/testData/codegen/boxInline/innerClasses/kt10259.kt index 87fc4d4125f..cb65b1b6d12 100644 --- a/compiler/testData/codegen/boxInline/innerClasses/kt10259.kt +++ b/compiler/testData/codegen/boxInline/innerClasses/kt10259.kt @@ -1,5 +1,6 @@ -// FILE: 1.kt +// NO_CHECK_LAMBDA_INLINING // WITH_RUNTIME +// FILE: 1.kt package test inline fun test(s: () -> Unit) { diff --git a/compiler/testData/codegen/boxInline/smap/newsmap/mappingInSubInlineLambda.kt b/compiler/testData/codegen/boxInline/smap/newsmap/mappingInSubInlineLambda.kt index 94873cd3d78..593cc2ea506 100644 --- a/compiler/testData/codegen/boxInline/smap/newsmap/mappingInSubInlineLambda.kt +++ b/compiler/testData/codegen/boxInline/smap/newsmap/mappingInSubInlineLambda.kt @@ -1,5 +1,5 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt - package test inline fun test(s: () -> Unit) { diff --git a/compiler/testData/codegen/boxInline/smap/newsmap/mappingInSubInlineLambdaSameFileInline.kt b/compiler/testData/codegen/boxInline/smap/newsmap/mappingInSubInlineLambdaSameFileInline.kt index 8d7265f73b2..f5a7c59925b 100644 --- a/compiler/testData/codegen/boxInline/smap/newsmap/mappingInSubInlineLambdaSameFileInline.kt +++ b/compiler/testData/codegen/boxInline/smap/newsmap/mappingInSubInlineLambdaSameFileInline.kt @@ -1,5 +1,5 @@ +// NO_CHECK_LAMBDA_INLINING // FILE: 1.kt - package test inline fun test(s: () -> Unit) { diff --git a/compiler/testData/codegen/boxInline/trait/trait.kt b/compiler/testData/codegen/boxInline/trait/trait.kt index c44a59048cd..cd85fac3b3e 100644 --- a/compiler/testData/codegen/boxInline/trait/trait.kt +++ b/compiler/testData/codegen/boxInline/trait/trait.kt @@ -4,10 +4,18 @@ package test interface InlineTrait { - fun finalInline(s: () -> String): String { + private inline fun privateInline(s: () -> String): String { return s() } + fun testPrivateInline(): String { + return privateInline { "private" } + } + + fun testPrivateInline2(): String { + return privateInline { "private2" } + } + companion object { inline final fun finalInline(s: () -> String): String { return s() @@ -15,7 +23,7 @@ interface InlineTrait { } } -class Z: InlineTrait { +class Z : InlineTrait { } @@ -23,21 +31,13 @@ class Z: InlineTrait { import test.* -fun testFinalInline(): String { - return Z().finalInline({"final"}) -} - -fun testFinalInline2(instance: InlineTrait): String { - return instance.finalInline({"final2"}) -} - fun testClassObject(): String { - return InlineTrait.finalInline({"classobject"}) + return InlineTrait.finalInline({ "classobject" }) } fun box(): String { - if (testFinalInline() != "final") return "test1: ${testFinalInline()}" - if (testFinalInline2(Z()) != "final2") return "test2: ${testFinalInline2(Z())}" + if (Z().testPrivateInline() != "private") return "test1: ${Z().testPrivateInline()}" + if (Z().testPrivateInline2() != "private2") return "test2: ${Z().testPrivateInline2()}" if (testClassObject() != "classobject") return "test3: ${testClassObject()}" return "OK" diff --git a/compiler/tests-common/org/jetbrains/kotlin/codegen/InlineTestUtil.kt b/compiler/tests-common/org/jetbrains/kotlin/codegen/InlineTestUtil.kt index 4deef636409..127cdc4a50b 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/codegen/InlineTestUtil.kt +++ b/compiler/tests-common/org/jetbrains/kotlin/codegen/InlineTestUtil.kt @@ -40,7 +40,7 @@ object InlineTestUtil { val skipParameterChecking = sourceFiles.any { InTextDirectivesUtils.isDirectiveDefined(it.text, "NO_CHECK_LAMBDA_INLINING") - } + } || !doLambdaInliningCheck(files, inlineInfo) if (!skipParameterChecking) { val notInlinedParameters = checkParametersInlined(files, inlineInfo) @@ -54,20 +54,16 @@ object InlineTestUtil { private fun obtainInlineInfo(files: Iterable): InlineInfo { val inlineMethods = HashSet() val binaryClasses = hashMapOf() - for (file in files) { val binaryClass = loadBinaryClass(file) val inlineFunctions = inlineFunctionsJvmNames(binaryClass.classHeader) val classVisitor = object : ClassVisitorWithName() { - override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor { - return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) { - override fun visitEnd() { - if (name + desc in inlineFunctions) { - inlineMethods.add(MethodInfo(className, name, this.desc)) - } - } + override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { + if (name + desc in inlineFunctions) { + inlineMethods.add(MethodInfo(className, name, desc)) } + return null } } @@ -78,6 +74,34 @@ object InlineTestUtil { return InlineInfo(inlineMethods, binaryClasses) } + private fun doLambdaInliningCheck(files: Iterable, inlineInfo: InlineInfo): Boolean { + var doLambdaInliningCheck = true + for (file in files) { + val binaryClass = loadBinaryClass(file) + val inlineFunctions = inlineFunctionsJvmNames(binaryClass.classHeader) + + val classVisitor = object : ClassVisitorWithName() { + override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { + if (name + desc in inlineFunctions) { + return object: MethodNodeWithAnonymousObjectCheck(inlineInfo, access, name, desc, signature, exceptions) { + override fun onAnonymousConstructorCallOrSingletonAccess(owner: String) { + doLambdaInliningCheck = false + } + } + } + return null + } + } + + ClassReader(file.asByteArray()).accept(classVisitor, 0) + + if (!doLambdaInliningCheck) break + } + + return doLambdaInliningCheck + } + + private fun checkInlineMethodNotInvoked(files: Iterable, inlinedMethods: Set): List { val notInlined = ArrayList() @@ -139,23 +163,10 @@ object InlineTestUtil { return null } - return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) { - private fun isInlineParameterLikeOwner(owner: String) = - "$" in owner && !isTopLevelOrInnerOrPackageClass(owner, inlineInfo) - - override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) { - if ("".equals(name) && isInlineParameterLikeOwner(owner)) { - val fromCall = MethodInfo(className, this.name, this.desc) - notInlinedParameters.add(NotInlinedParameter(owner, fromCall)) - } - } - - override fun visitFieldInsn(opcode: Int, owner: String, name: String, desc: String) { - if (opcode == Opcodes.GETSTATIC && isInlineParameterLikeOwner(owner)) { - val fromCall = MethodInfo(className, this.name, this.desc) - notInlinedParameters.add(NotInlinedParameter(owner, fromCall)) - } - super.visitFieldInsn(opcode, owner, name, desc) + return object: MethodNodeWithAnonymousObjectCheck(inlineInfo, access, name, desc, signature, exceptions) { + override fun onAnonymousConstructorCallOrSingletonAccess(owner: String) { + val fromCall = MethodInfo(className, this.name, this.desc) + notInlinedParameters.add(NotInlinedParameter(owner, fromCall)) } } } @@ -174,6 +185,8 @@ object InlineTestUtil { private fun isClassOrPackagePartKind(klass: KotlinJvmBinaryClass): Boolean { return klass.classHeader.kind == KotlinClassHeader.Kind.CLASS && !klass.classId.isLocal + || klass.classHeader.kind == KotlinClassHeader.Kind.FILE_FACADE /*single file facade equals to package part*/ + || klass.classHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART } private fun loadBinaryClass(file: OutputFile): KotlinJvmBinaryClass { @@ -207,4 +220,24 @@ object InlineTestUtil { super.visit(version, access, name, signature, superName, interfaces) } } + + private abstract class MethodNodeWithAnonymousObjectCheck(val inlineInfo: InlineInfo, access: Int, name: String, desc: String, signature: String?, exceptions: Array?) : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) { + private fun isInlineParameterLikeOwner(owner: String) = + "$" in owner && !isTopLevelOrInnerOrPackageClass(owner, inlineInfo) + + override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) { + if ("" == name && isInlineParameterLikeOwner(owner)) { + onAnonymousConstructorCallOrSingletonAccess(owner) + } + } + + abstract fun onAnonymousConstructorCallOrSingletonAccess(owner: String) + + override fun visitFieldInsn(opcode: Int, owner: String, name: String, desc: String) { + if (opcode == Opcodes.GETSTATIC && isInlineParameterLikeOwner(owner)) { + onAnonymousConstructorCallOrSingletonAccess(owner) + } + super.visitFieldInsn(opcode, owner, name, desc) + } + } }