Never delete types from inline functions during inline transformations
#KT-19399 Fixed
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.InlineCycleReporter
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import java.util.*
|
||||
|
||||
class GlobalInlineContext(diagnostics: DiagnosticSink) {
|
||||
|
||||
private val inlineCycleReporter: InlineCycleReporter = InlineCycleReporter(diagnostics)
|
||||
|
||||
private val typesUsedInInlineFunctions = LinkedList<MutableSet<String>>()
|
||||
|
||||
fun enterIntoInlining(call: ResolvedCall<*>?) =
|
||||
inlineCycleReporter.enterIntoInlining(call).also {
|
||||
if (it) typesUsedInInlineFunctions.push(hashSetOf())
|
||||
}
|
||||
|
||||
fun exitFromInliningOf(call: ResolvedCall<*>?) {
|
||||
inlineCycleReporter.exitFromInliningOf(call)
|
||||
val pop = typesUsedInInlineFunctions.pop()
|
||||
typesUsedInInlineFunctions.peek()?.addAll(pop)
|
||||
}
|
||||
|
||||
fun recordTypeFromInlineFunction(type: String) = typesUsedInInlineFunctions.peek().add(type)
|
||||
|
||||
fun isTypeFromInlineFunction(type: String) = typesUsedInInlineFunctions.peek().contains(type)
|
||||
}
|
||||
@@ -652,14 +652,14 @@ class PsiInlineCodegen(
|
||||
callDefault: Boolean,
|
||||
codegen: ExpressionCodegen
|
||||
) {
|
||||
if (!state.inlineCycleReporter.enterIntoInlining(resolvedCall)) {
|
||||
if (!state.globalInlineContext.enterIntoInlining(resolvedCall)) {
|
||||
generateStub(resolvedCall, codegen)
|
||||
return
|
||||
}
|
||||
try {
|
||||
performInline(resolvedCall?.typeArguments, callDefault, codegen)
|
||||
} finally {
|
||||
state.inlineCycleReporter.exitFromInliningOf(resolvedCall)
|
||||
state.globalInlineContext.exitFromInliningOf(resolvedCall)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,13 @@ class MethodInliner(
|
||||
return doInline(adapter, remapper, remapReturn, labelOwner, 0)
|
||||
}
|
||||
|
||||
private fun recordTransformation(info: TransformationInfo) {
|
||||
if (!inliningContext.isInliningLambda) {
|
||||
inliningContext.root.state.globalInlineContext.recordTypeFromInlineFunction(info.oldClassName)
|
||||
}
|
||||
transformations.add(info)
|
||||
}
|
||||
|
||||
private fun doInline(
|
||||
adapter: MethodVisitor,
|
||||
remapper: LocalVarRemapper,
|
||||
@@ -160,7 +167,9 @@ class MethodInliner(
|
||||
|
||||
if (inliningContext.isInliningLambda &&
|
||||
inliningContext.lambdaInfo !is DefaultLambda && //never delete default lambda classes
|
||||
transformationInfo!!.canRemoveAfterTransformation()) {
|
||||
transformationInfo!!.canRemoveAfterTransformation() &&
|
||||
!inliningContext.root.state.globalInlineContext.isTypeFromInlineFunction(oldClassName)
|
||||
) {
|
||||
// this class is transformed and original not used so we should remove original one after inlining
|
||||
result.addClassToRemove(oldClassName)
|
||||
}
|
||||
@@ -452,7 +461,7 @@ class MethodInliner(
|
||||
invokeCalls.add(InvokeCall(lambdaInfo, currentFinallyDeep))
|
||||
}
|
||||
else if (isSamWrapperConstructorCall(owner, name)) {
|
||||
transformations.add(SamWrapperTransformationInfo(owner, inliningContext, isAlreadyRegenerated(owner)))
|
||||
recordTransformation(SamWrapperTransformationInfo(owner, inliningContext, isAlreadyRegenerated(owner)))
|
||||
}
|
||||
else if (isAnonymousConstructorCall(owner, name)) {
|
||||
val lambdaMapping = HashMap<Int, LambdaInfo>()
|
||||
@@ -473,7 +482,7 @@ class MethodInliner(
|
||||
offset += if (i == 0) 1 else argTypes[i - 1].size
|
||||
}
|
||||
|
||||
transformations.add(
|
||||
recordTransformation(
|
||||
buildConstructorInvocation(
|
||||
owner, cur.desc, lambdaMapping, awaitClassReification, capturesAnonymousObjectThatMustBeRegenerated
|
||||
)
|
||||
@@ -491,7 +500,7 @@ class MethodInliner(
|
||||
val fieldInsnNode = cur as FieldInsnNode?
|
||||
val className = fieldInsnNode!!.owner
|
||||
if (isAnonymousSingletonLoad(className, fieldInsnNode.name)) {
|
||||
transformations.add(
|
||||
recordTransformation(
|
||||
AnonymousObjectTransformationInfo(
|
||||
className, awaitClassReification, isAlreadyRegenerated(className), true,
|
||||
inliningContext.nameGenerator
|
||||
@@ -500,7 +509,7 @@ class MethodInliner(
|
||||
awaitClassReification = false
|
||||
}
|
||||
else if (isWhenMappingAccess(className, fieldInsnNode.name)) {
|
||||
transformations.add(
|
||||
recordTransformation(
|
||||
WhenMappingTransformationInfo(
|
||||
className, inliningContext.nameGenerator, isAlreadyRegenerated(className), fieldInsnNode
|
||||
)
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContext
|
||||
import org.jetbrains.kotlin.codegen.context.RootContext
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.codegen.inline.GlobalInlineContext
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCache
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.optimization.OptimizationClassBuilderFactory
|
||||
@@ -196,7 +197,7 @@ class GenerationState private constructor(
|
||||
IntrinsicMethods(target, shouldUseConsistentEquals)
|
||||
}
|
||||
val samWrapperClasses: SamWrapperClasses = SamWrapperClasses(this)
|
||||
val inlineCycleReporter: InlineCycleReporter = InlineCycleReporter(diagnostics)
|
||||
val globalInlineContext: GlobalInlineContext = GlobalInlineContext(diagnostics)
|
||||
val mappingsClassesForWhenByEnum: MappingsClassesForWhenByEnum = MappingsClassesForWhenByEnum(this)
|
||||
val jvmRuntimeTypes: JvmRuntimeTypes = JvmRuntimeTypes(module)
|
||||
val factory: ClassFileFactory
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//WITH_RUNTIME
|
||||
// FILE: 1.kt
|
||||
class Foo {
|
||||
var bar = ""
|
||||
|
||||
inline fun ifNotBusyPerform(action: (complete: () -> Unit) -> Unit) {
|
||||
action {
|
||||
bar += "K"
|
||||
}
|
||||
}
|
||||
|
||||
fun ifNotBusySayHello() {
|
||||
ifNotBusyPerform {
|
||||
bar += "O"
|
||||
it()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun inlineFun(s: () -> Unit) {
|
||||
s()
|
||||
}
|
||||
|
||||
fun start() {
|
||||
inlineFun {
|
||||
{
|
||||
ifNotBusyPerform {
|
||||
ifNotBusySayHello()
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: 2.kt
|
||||
|
||||
fun box(): String {
|
||||
val foo = Foo()
|
||||
foo.start()
|
||||
|
||||
return foo.bar
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fun test() {
|
||||
{
|
||||
{}()
|
||||
}()
|
||||
}
|
||||
|
||||
inline fun ifun(s: () -> Unit) {
|
||||
s()
|
||||
}
|
||||
|
||||
fun test2() {
|
||||
var z = 1;
|
||||
ifun {
|
||||
{ z = 2 }()
|
||||
}
|
||||
}
|
||||
|
||||
// 1 class DeleteClassOnTransfromationKt\$test\$1\$1
|
||||
// 0 class DeleteClassOnTransfromationKt\$test2\$1\$1
|
||||
+6
@@ -201,6 +201,12 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19399.kt")
|
||||
public void testKt19399() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19434.kt")
|
||||
public void testKt19434() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
||||
|
||||
+6
@@ -201,6 +201,12 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19399.kt")
|
||||
public void testKt19399() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19434.kt")
|
||||
public void testKt19434() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
||||
|
||||
+6
@@ -201,6 +201,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19399.kt")
|
||||
public void testKt19399() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19434.kt")
|
||||
public void testKt19434() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
||||
|
||||
@@ -1821,6 +1821,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/inline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("deleteClassOnTransfromation.kt")
|
||||
public void testDeleteClassOnTransfromation() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/deleteClassOnTransfromation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("finallyMarkers.kt")
|
||||
public void testFinallyMarkers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inline/finallyMarkers.kt");
|
||||
|
||||
Generated
+6
@@ -201,6 +201,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19399.kt")
|
||||
public void testKt19399() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19399.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt19434.kt")
|
||||
public void testKt19434() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/kt19434.kt");
|
||||
|
||||
Reference in New Issue
Block a user