diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt index 6756e9b6696..e64accae2e5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt @@ -10,7 +10,9 @@ import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.coroutines.DEBUG_METADATA_ANNOTATION_ASM_TYPE import org.jetbrains.kotlin.codegen.coroutines.isCapturedSuspendLambda import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass +import org.jetbrains.kotlin.codegen.coroutines.isResumeImplMethodName import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer +import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass @@ -244,7 +246,14 @@ class AnonymousObjectTransformer( private fun writeOuterInfo(visitor: ClassVisitor) { val info = inliningContext.callSiteInfo - visitor.visitOuterClass(info.ownerClassName, info.functionName, info.functionDesc) + // Since $$forInline functions are not generated if retransformation is the last one (i.e. call site is not inline) + // link to the function in OUTERCLASS field becomes invalid. However, since $$forInline function always has no-inline + // companion without the suffix, use it. + if (info.isSuspend && info.isInlineOrInsideInline) { + visitor.visitOuterClass(info.ownerClassName, info.functionName?.removeSuffix(FOR_INLINE_SUFFIX), info.functionDesc) + } else { + visitor.visitOuterClass(info.ownerClassName, info.functionName, info.functionDesc) + } } private fun inlineMethodAndUpdateGlobalResult( @@ -288,7 +297,8 @@ class AnonymousObjectTransformer( transformationInfo.oldClassName, sourceNode.name, if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc, - inliningContext.callSiteInfo.isInlineOrInsideInline + inliningContext.callSiteInfo.isInlineOrInsideInline, + isSuspendFunctionOrLambda(sourceNode) ), null ) @@ -298,6 +308,12 @@ class AnonymousObjectTransformer( return result } + private fun isSuspendFunctionOrLambda(sourceNode: MethodNode): Boolean = + (sourceNode.desc.endsWith(";Lkotlin/coroutines/Continuation;)Ljava/lang/Object;") || + sourceNode.desc.endsWith(";Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;")) && + (CoroutineTransformer.findFakeContinuationConstructorClassName(sourceNode) != null || + languageVersionSettings.isResumeImplMethodName(sourceNode.name.removeSuffix(FOR_INLINE_SUFFIX))) + private fun generateConstructorAndFields( classBuilder: ClassBuilder, allCapturedBuilder: ParametersBuilder, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCallSiteInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCallSiteInfo.kt index 63fbc9f2b96..3516d01de69 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCallSiteInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCallSiteInfo.kt @@ -1,19 +1,14 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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 -class InlineCallSiteInfo(val ownerClassName: String, val functionName: String?, val functionDesc: String?, val isInlineOrInsideInline: Boolean) \ No newline at end of file +class InlineCallSiteInfo( + val ownerClassName: String, + val functionName: String?, + val functionDesc: String?, + val isInlineOrInsideInline: Boolean, + val isSuspend: Boolean +) \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt index 3a08af11f41..10cd9a50001 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -122,7 +122,11 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid val signature = codegen.state.typeMapper.mapSignatureSkipGeneric(context.functionDescriptor, context.contextKind) return InlineCallSiteInfo( - parentCodegen.className, signature.asmMethod.name, signature.asmMethod.descriptor, compilationContextFunctionDescriptor.isInlineOrInsideInline() + parentCodegen.className, + signature.asmMethod.name, + signature.asmMethod.descriptor, + compilationContextFunctionDescriptor.isInlineOrInsideInline(), + compilationContextFunctionDescriptor.isSuspend ) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt index f93c3c12372..5764a881ff2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.backend.jvm.codegen @@ -65,7 +54,7 @@ class IrSourceCompilerForInline( get() = OwnerKind.getMemberOwnerKind(callElement.descriptor.containingDeclaration) override val inlineCallSiteInfo: InlineCallSiteInfo - get() = InlineCallSiteInfo("TODO", null, null, false) + get() = InlineCallSiteInfo("TODO", null, null, false, false) override val lazySourceMapper: DefaultSourceMapper get() = codegen.classCodegen.getOrCreateSourceMapper() diff --git a/compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt b/compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt new file mode 100644 index 00000000000..5e59d373816 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt @@ -0,0 +1,60 @@ +// IGNORE_BACKEND: JVM_IR +// TARGET_BACKEND: JVM +// FILE: flow.kt +// COMMON_COROUTINES_TEST +// FULL_JDK +// WITH_RUNTIME +// WITH_COROUTINES + +package flow + +interface FlowCollector { + suspend fun emit(value: T) +} + +interface Flow { + suspend fun collect(collector: FlowCollector) +} + +public inline fun flow(crossinline block: suspend FlowCollector.() -> Unit) = object : Flow { + override suspend fun collect(collector: FlowCollector) = collector.block() +} + +suspend inline fun Flow.collect(crossinline action: suspend (T) -> Unit): Unit = + collect(object : FlowCollector { + override suspend fun emit(value: T) = action(value) + }) + +public inline fun Flow.transform(crossinline transformer: suspend FlowCollector.(value: T) -> Unit): Flow { + return flow { + collect { value -> + transformer(value) + } + } +} + +public inline fun Flow.map(crossinline transformer: suspend (value: T) -> R): Flow = transform { value -> emit(transformer(value)) } + +inline fun decorate() = suspend { + flow { + emit(1) + }.map { it + 1 } + .collect { + } +} + +// FILE: box.kt +// COMMON_COROUTINES_TEST + +import flow.* + +fun box() : String { + decorate() + val enclosingMethod = try { + Class.forName("flow.FlowKt\$decorate\$1\$invokeSuspend\$\$inlined\$map\$1\$1").enclosingMethod + } catch (ignore: ClassNotFoundException) { + Class.forName("flow.FlowKt\$decorate\$1\$doResume\$\$inlined\$map\$1\$1").enclosingMethod + } + if ("$enclosingMethod".contains("\$\$forInline")) return "$enclosingMethod" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index 8899c32ba40..8da7cf8b7d9 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -3430,6 +3430,16 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines"); } + @TestMetadata("enclodingMethod.kt") + public void testEnclodingMethod_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("enclodingMethod.kt") + public void testEnclodingMethod_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt", "kotlin.coroutines"); + } + @TestMetadata("fileNameInMetadata.kt") public void testFileNameInMetadata() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/fileNameInMetadata.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index 249eba66637..8b80a2f79f2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3430,6 +3430,16 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines"); } + @TestMetadata("enclodingMethod.kt") + public void testEnclodingMethod_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("enclodingMethod.kt") + public void testEnclodingMethod_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt", "kotlin.coroutines"); + } + @TestMetadata("fileNameInMetadata.kt") public void testFileNameInMetadata() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/fileNameInMetadata.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 5ef8f18f5b5..33a76545dec 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -3430,6 +3430,16 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt", "kotlin.coroutines"); } + @TestMetadata("enclodingMethod.kt") + public void testEnclodingMethod_1_2() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt", "kotlin.coroutines.experimental"); + } + + @TestMetadata("enclodingMethod.kt") + public void testEnclodingMethod_1_3() throws Exception { + runTestWithPackageReplacement("compiler/testData/codegen/boxInline/suspend/enclodingMethod.kt", "kotlin.coroutines"); + } + @TestMetadata("fileNameInMetadata.kt") public void testFileNameInMetadata() throws Exception { runTest("compiler/testData/codegen/boxInline/suspend/fileNameInMetadata.kt");