From 8a5ae1694743653c9018ac746f0384d3b2a8f4a1 Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Wed, 4 Apr 2018 22:30:30 +0300 Subject: [PATCH] Generate separate methods for inline and noinline uses of inline suspend functions Previously, inline suspend functions were effectively inline only, but ordinary inline functions can be used as noinline. To fix the issue, I generate two functions: one for inline with suffix $$forInline and without state machine; and the other one without any suffix and state machine for direct calls. This change does not affect effectively inline only suspend functions, i.e. functions with reified generics, annotated with @InlineOnly annotation and functions with crossinline parameters. #KT-20219: Fixed --- .../kotlin/codegen/FunctionCodegen.java | 58 +++++++--- .../SuspendFunctionGenerationStrategy.kt | 6 +- ...SuspendInlineFunctionGenerationStrategy.kt | 105 ++++++++++++++++++ .../kotlin/codegen/inline/InlineCodegen.kt | 22 +++- .../multiModule/inlineMultiModuleOverride.kt | 1 - .../inlineWithStateMachine.txt | 20 +++- .../inlineWithoutStateMachine.txt | 3 +- .../inlineUsedAsNoinline/inlineOnly.kt | 71 ++++++++++++ .../inlineUsedAsNoinline/simpleNamed.kt | 69 ++++++++++++ .../bytecodeListing/inline/simpleNamed.kt | 39 +++++++ .../bytecodeListing/inline/simpleNamed.txt | 32 ++++++ .../codegen/AbstractLightAnalysisModeTest.kt | 1 + .../kotlin/codegen/InlineTestUtil.kt | 3 + .../ir/IrBlackBoxCodegenTestGenerated.java | 16 +-- .../IrBlackBoxInlineCodegenTestGenerated.java | 23 ++++ ...otlinAgainstInlineKotlinTestGenerated.java | 23 ++++ .../codegen/BlackBoxCodegenTestGenerated.java | 16 +-- .../BlackBoxInlineCodegenTestGenerated.java | 23 ++++ .../codegen/BytecodeListingTestGenerated.java | 18 +++ ...otlinAgainstInlineKotlinTestGenerated.java | 23 ++++ .../LightAnalysisModeTestGenerated.java | 36 ++---- .../descriptors/annotations/annotationUtil.kt | 2 +- 22 files changed, 528 insertions(+), 82 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt create mode 100644 compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt create mode 100644 compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt create mode 100644 compiler/testData/codegen/bytecodeListing/inline/simpleNamed.kt create mode 100644 compiler/testData/codegen/bytecodeListing/inline/simpleNamed.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java index 0040217e165..13077885a60 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/FunctionCodegen.java @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; import org.jetbrains.kotlin.codegen.coroutines.SuspendFunctionGenerationStrategy; +import org.jetbrains.kotlin.codegen.coroutines.SuspendInlineFunctionGenerationStrategy; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.config.JvmDefaultMode; @@ -29,6 +30,7 @@ import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.Annotated; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget; +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt; import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl; import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature; @@ -126,16 +128,28 @@ public class FunctionCodegen { if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) { FunctionGenerationStrategy strategy; - if (functionDescriptor.isSuspend() && !functionDescriptor.isInline()) { - strategy = new SuspendFunctionGenerationStrategy( - state, - CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(functionDescriptor), - function, - v.getThisName(), - state.getConstructorCallNormalizationMode() - ); - } - else { + if (functionDescriptor.isSuspend()) { + if (AnnotationUtilKt.isEffectivelyInlineOnly(functionDescriptor)) { + strategy = new FunctionGenerationStrategy.FunctionDefault(state, function); + } else if (!functionDescriptor.isInline()) { + strategy = new SuspendFunctionGenerationStrategy( + state, + CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(functionDescriptor), + function, + v.getThisName(), + state.getConstructorCallNormalizationMode() + ); + } else { + strategy = new SuspendInlineFunctionGenerationStrategy( + state, + CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(functionDescriptor), + function, + v.getThisName(), + state.getConstructorCallNormalizationMode(), + this + ); + } + } else { strategy = new FunctionGenerationStrategy.FunctionDefault(state, function); } @@ -202,12 +216,12 @@ public class FunctionCodegen { MethodVisitor mv = strategy.wrapMethodVisitor( - v.newMethod(origin, - flags, - asmMethod.getName(), - asmMethod.getDescriptor(), - jvmSignature.getGenericsSignature(), - getThrownExceptions(functionDescriptor, typeMapper) + newMethod(origin, + flags, + asmMethod.getName(), + asmMethod.getDescriptor(), + jvmSignature.getGenericsSignature(), + getThrownExceptions(functionDescriptor, typeMapper) ), flags, asmMethod.getName(), asmMethod.getDescriptor() @@ -254,6 +268,18 @@ public class FunctionCodegen { } } + @NotNull + public MethodVisitor newMethod( + @NotNull JvmDeclarationOrigin origin, + int access, + @NotNull String name, + @NotNull String desc, + @Nullable String signature, + @Nullable String[] exceptions + ) { + return v.newMethod(origin, access, name, desc, signature, exceptions); + } + private static boolean shouldDelegateMethodBodyToInlineClass( @NotNull JvmDeclarationOrigin origin, @NotNull FunctionDescriptor functionDescriptor, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt index 8541f5ab727..dc218ee3563 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendFunctionGenerationStrategy.kt @@ -28,10 +28,10 @@ import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.tree.MethodNode -class SuspendFunctionGenerationStrategy( +open class SuspendFunctionGenerationStrategy( state: GenerationState, - private val originalSuspendDescriptor: FunctionDescriptor, - private val declaration: KtFunction, + protected val originalSuspendDescriptor: FunctionDescriptor, + protected val declaration: KtFunction, private val containingClassInternalName: String, private val constructorCallNormalizationMode: JVMConstructorCallNormalizationMode ) : FunctionGenerationStrategy.CodegenBased(state) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt new file mode 100644 index 00000000000..65438994899 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/SuspendInlineFunctionGenerationStrategy.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2010-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.coroutines + +import org.jetbrains.kotlin.codegen.ExpressionCodegen +import org.jetbrains.kotlin.codegen.FunctionCodegen +import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy +import org.jetbrains.kotlin.codegen.TransformationMethodVisitor +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.org.objectweb.asm.MethodVisitor +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.tree.MethodNode + +// For named suspend function we generate two methods: +// 1) to use as noinline function, which have state machine +// 2) to use from inliner: private one without state machine +class SuspendInlineFunctionGenerationStrategy( + state: GenerationState, + originalSuspendDescriptor: FunctionDescriptor, + declaration: KtFunction, + containingClassInternalName: String, + constructorCallNormalizationMode: JVMConstructorCallNormalizationMode, + private val codegen: FunctionCodegen +) : SuspendFunctionGenerationStrategy( + state, + originalSuspendDescriptor, + declaration, + containingClassInternalName, + constructorCallNormalizationMode +) { + private val defaultStrategy = FunctionGenerationStrategy.FunctionDefault(state, declaration) + + override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor { + if (access and Opcodes.ACC_ABSTRACT != 0) return mv + + return MethodNodeCopyingMethodVisitor( + super.wrapMethodVisitor(mv, access, name, desc), + access, + name, + desc = desc, + signature = null, + exceptions = null, + codegen = codegen, + declaration = declaration, + originalSuspendDescriptor = originalSuspendDescriptor, + isReleaseCoroutines = state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) + ) + } + + override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) { + super.doGenerateBody(codegen, signature) + defaultStrategy.doGenerateBody(codegen, signature) + } + + private class MethodNodeCopyingMethodVisitor( + delegate: MethodVisitor, + private val access: Int, + private val name: String, + private val desc: String, + private val signature: String?, + private val exceptions: Array?, + private val codegen: FunctionCodegen, + private val declaration: KtFunction, + private val originalSuspendDescriptor: FunctionDescriptor, + private val isReleaseCoroutines: Boolean + ) : TransformationMethodVisitor( + delegate, + calculateAccessForInline(access), + "$name\$\$forInline", + desc, + signature, + exceptions + ) { + override fun performTransformations(methodNode: MethodNode) { + val newMethodNode = codegen.newMethod( + OtherOrigin(declaration, getOrCreateJvmSuspendFunctionView(originalSuspendDescriptor, isReleaseCoroutines)), + calculateAccessForInline(access), "$name\$\$forInline", desc, signature, exceptions + ) + methodNode.instructions.resetLabels() + methodNode.accept(newMethodNode) + } + } + + companion object { + private fun calculateAccessForInline(access: Int): Int { + var accessForInline = access + if (accessForInline and Opcodes.ACC_PUBLIC != 0) { + accessForInline = accessForInline xor Opcodes.ACC_PUBLIC + } + if (accessForInline and Opcodes.ACC_PROTECTED != 0) { + accessForInline = accessForInline xor Opcodes.ACC_PROTECTED + } + return accessForInline or Opcodes.ACC_PRIVATE + } + } +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index d55bbafafe3..303cbd159f5 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -503,7 +503,7 @@ abstract class InlineCodegen( val asmMethod = if (callDefault) state.typeMapper.mapDefaultMethod(functionDescriptor, sourceCompilerForInline.contextKind) else - jvmSignature.asmMethod + mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod) val methodId = MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.containingDeclaration), asmMethod) val directMember = getDirectMemberAndCallableFromObject(functionDescriptor) @@ -511,16 +511,26 @@ abstract class InlineCodegen( return sourceCompilerForInline.doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, callDefault, asmMethod) } - val resultInCache = state.inlineCache.methodNodeById.getOrPut( - methodId - ) { - doCreateMethodNodeFromCompiled(directMember, state, asmMethod) - ?: throw IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor) + val resultInCache = state.inlineCache.methodNodeById.getOrPut(methodId) { + val result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod) + ?: if (functionDescriptor.isSuspend) + doCreateMethodNodeFromCompiled(directMember, state, jvmSignature.asmMethod) + else + null + result ?: throw IllegalStateException("Couldn't obtain compiled function body for $functionDescriptor") } return resultInCache.copyWithNewNode(cloneMethodNode(resultInCache.node)) } + // For suspend inline functions we generate two methods: + // 1) normal one: with state machine to call directly + // 2) for inliner: with mangled name and without state machine + private fun mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor: FunctionDescriptor, asmMethod: Method): Method { + if (!functionDescriptor.isSuspend) return asmMethod + return Method("${asmMethod.name}\$\$forInline", asmMethod.descriptor) + } + private fun getDirectMemberAndCallableFromObject(functionDescriptor: FunctionDescriptor): CallableMemberDescriptor { val directMember = JvmCodegenUtil.getDirectMember(functionDescriptor) return (directMember as? ImportedFromObjectCallableDescriptor<*>)?.callableFromObject ?: directMember diff --git a/compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt b/compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt index bfb4943eeed..fd7e43f325c 100644 --- a/compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt +++ b/compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt @@ -1,6 +1,5 @@ // IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: NATIVE -// IGNORE_BACKEND: JVM // WITH_COROUTINES // WITH_RUNTIME // COMMON_COROUTINES_TEST diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.txt index 10bf75e84b6..dd1c2e0b921 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.txt @@ -23,13 +23,29 @@ final class InlineWithStateMachineKt$mainSuspend$1 { synthetic final method setLabel(p0: int): void } +@kotlin.Metadata +public final class InlineWithStateMachineKt$suspendHere$1 { + field L$0: java.lang.Object + field L$1: java.lang.Object + synthetic field data: java.lang.Object + synthetic field exception: java.lang.Throwable + inner class InlineWithStateMachineKt$suspendHere$1 + public method (p0: COROUTINES_PACKAGE.Continuation): void + public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object + synthetic final method getLabel(): int + synthetic final method setLabel(p0: int): void +} + @kotlin.Metadata public final class InlineWithStateMachineKt { inner class InlineWithStateMachineKt$box$1 inner class InlineWithStateMachineKt$mainSuspend$1 + inner class InlineWithStateMachineKt$suspendHere$1 public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void public final static @org.jetbrains.annotations.Nullable method mainSuspend(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object - private final static method suspendHere(p0: COROUTINES_PACKAGE.Continuation): java.lang.Object - private final static method suspendThere(p0: java.lang.String, p1: COROUTINES_PACKAGE.Continuation): java.lang.Object + private final static @org.jetbrains.annotations.Nullable method suspendHere$$forInline(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object + private final static @org.jetbrains.annotations.Nullable method suspendThere$$forInline(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: COROUTINES_PACKAGE.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: COROUTINES_PACKAGE.Continuation): java.lang.Object } diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithoutStateMachine.txt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithoutStateMachine.txt index 09ef8dcb272..99505265e8f 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithoutStateMachine.txt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithoutStateMachine.txt @@ -31,5 +31,6 @@ public final class InlineWithoutStateMachineKt { public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void public final static @org.jetbrains.annotations.Nullable method complexSuspend(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: COROUTINES_PACKAGE.Continuation): java.lang.Object - private final static method suspendThere(p0: java.lang.String, p1: COROUTINES_PACKAGE.Continuation): java.lang.Object + private final static @org.jetbrains.annotations.Nullable method suspendThere$$forInline(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: COROUTINES_PACKAGE.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: COROUTINES_PACKAGE.Continuation): java.lang.Object } diff --git a/compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt b/compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt new file mode 100644 index 00000000000..960e8234336 --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt @@ -0,0 +1,71 @@ +// FILE: inlined.kt +// WITH_RUNTIME +// NO_CHECK_LAMBDA_INLINING + +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +var result = "FAIL" +var i = 0 +var finished = false + +var proceed: () -> Unit = {} + +suspend fun suspendHere() = suspendCoroutine { + i++ + proceed = { it.resume(Unit) } +} + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +@kotlin.internal.InlineOnly +inline suspend fun inlineMe() { + suspendHere() + suspendHere() + suspendHere() + suspendHere() + suspendHere() +} + +// FILE: inlineSite.kt + +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +fun builder(c: suspend () -> Unit) { + val continuation = object: Continuation { + override val context: CoroutineContext + get() = EmptyCoroutineContext + + override fun resume(value: Unit) { + proceed = { + result = "OK" + finished = true + } + } + + override fun resumeWithException(exception: Throwable) { + throw exception + } + } + c.startCoroutine(continuation) +} + +suspend fun inlineSite() { + inlineMe() + inlineMe() +} + +fun box(): String { + builder { + inlineSite() + } + for (counter in 0 until 10) { + if (i != counter + 1) return "Expected ${counter + 1}, got $i" + proceed() + } + if (i != 10) return "FAIL $i" + if (finished) return "resume on root continuation is called" + proceed() + if (!finished) return "resume on root continuation is not called" + return result +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt b/compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt new file mode 100644 index 00000000000..9d5976cee2c --- /dev/null +++ b/compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt @@ -0,0 +1,69 @@ +// FILE: inlined.kt +// WITH_RUNTIME +// NO_CHECK_LAMBDA_INLINING + +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +var result = "FAIL" +var i = 0 +var finished = false + +var proceed: () -> Unit = {} + +suspend fun suspendHere() = suspendCoroutine { + i++ + proceed = { it.resume(Unit) } +} + +inline suspend fun inlineMe() { + suspendHere() + suspendHere() + suspendHere() + suspendHere() + suspendHere() +} + +// FILE: inlineSite.kt + +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +fun builder(c: suspend () -> Unit) { + val continuation = object: Continuation { + override val context: CoroutineContext + get() = EmptyCoroutineContext + + override fun resume(value: Unit) { + proceed = { + result = "OK" + finished = true + } + } + + override fun resumeWithException(exception: Throwable) { + throw exception + } + } + c.startCoroutine(continuation) +} + +suspend fun inlineSite() { + inlineMe() + inlineMe() +} + +fun box(): String { + builder { + inlineSite() + } + for (counter in 0 until 10) { + if (i != counter + 1) return "Expected ${counter + 1}, got $i" + proceed() + } + if (i != 10) return "FAIL $i" + if (finished) return "resume on root continuation is called" + proceed() + if (!finished) return "resume on root continuation is not called" + return result +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/inline/simpleNamed.kt b/compiler/testData/codegen/bytecodeListing/inline/simpleNamed.kt new file mode 100644 index 00000000000..d67bd824b90 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/inline/simpleNamed.kt @@ -0,0 +1,39 @@ +// WITH_RUNTIME + +suspend inline fun simple() {} + +suspend inline fun generic() {} + +suspend inline fun genericWithReified() {} + +suspend inline fun Unit.simple() {} + +suspend inline fun T.generic() {} + +suspend inline fun T.genericWithReified() {} + +@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") +@kotlin.internal.InlineOnly +suspend inline fun shouldNotHaveSuffix() {} + +suspend inline fun acceptsCrossinline(crossinline c: () -> Unit) {} + +class Foo { + suspend inline fun simple() {} + + suspend inline fun generic() {} + + suspend inline fun genericWithReified() {} + + suspend inline fun Unit.simple() {} + + suspend inline fun T.generic() {} + + suspend inline fun T.genericWithReified() {} + + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + @kotlin.internal.InlineOnly + suspend inline fun shouldNotHaveSuffix() {} + + suspend inline fun acceptsCrossinline(crossinline c: () -> Unit) {} +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/inline/simpleNamed.txt b/compiler/testData/codegen/bytecodeListing/inline/simpleNamed.txt new file mode 100644 index 00000000000..94d4812e130 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/inline/simpleNamed.txt @@ -0,0 +1,32 @@ +@kotlin.Metadata +public final class Foo { + public method (): void + private final method acceptsCrossinline(p0: kotlin.jvm.functions.Function0, p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final @org.jetbrains.annotations.Nullable method generic$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final @org.jetbrains.annotations.Nullable method generic$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final @org.jetbrains.annotations.Nullable method generic(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final method genericWithReified(p0: java.lang.Object, p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final method genericWithReified(p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final @kotlin.internal.InlineOnly method shouldNotHaveSuffix(p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final @org.jetbrains.annotations.Nullable method simple$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.Unit, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final @org.jetbrains.annotations.Nullable method simple$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final @org.jetbrains.annotations.Nullable method simple(@org.jetbrains.annotations.NotNull p0: kotlin.Unit, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final @org.jetbrains.annotations.Nullable method simple(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object +} + +@kotlin.Metadata +public final class SimpleNamedKt { + private final static method acceptsCrossinline(p0: kotlin.jvm.functions.Function0, p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final static @org.jetbrains.annotations.Nullable method generic$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final static @org.jetbrains.annotations.Nullable method generic$$forInline(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.Nullable method generic(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final static method genericWithReified(p0: java.lang.Object, p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final static method genericWithReified(p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final static @kotlin.internal.InlineOnly method shouldNotHaveSuffix(p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final static @org.jetbrains.annotations.Nullable method simple$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.Unit, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + private final static @org.jetbrains.annotations.Nullable method simple$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.Nullable method simple(@org.jetbrains.annotations.NotNull p0: kotlin.Unit, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.Nullable method simple(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object +} diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLightAnalysisModeTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLightAnalysisModeTest.kt index 9c4dd8ec939..825211b4dda 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLightAnalysisModeTest.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/AbstractLightAnalysisModeTest.kt @@ -107,6 +107,7 @@ abstract class AbstractLightAnalysisModeTest : CodegenTestCase() { override fun shouldWriteMethod(access: Int, name: String, desc: String) = when { name == "" -> false + name.contains("\$\$forInline") -> false AsmTypes.DEFAULT_CONSTRUCTOR_MARKER.descriptor in desc -> false name.startsWith("access$") && (access and ACC_STATIC != 0) && (access and ACC_SYNTHETIC != 0) -> false else -> true diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt index d4713326204..0719a40cd8c 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt @@ -128,6 +128,9 @@ object InlineTestUtil { if (skipMethodsOfThisClass) { return null } + if (name == "doResume" && desc == "(Ljava/lang/Object;Ljava/lang/Throwable;)Ljava/lang/Object;") { + return null + } return object : MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions) { override fun visitMethodInsn(opcode: Int, owner: String, name: String, desc: String, itf: Boolean) { diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index f2dd2def78f..b35ba67e2fa 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -7059,25 +7059,13 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes @TestMetadata("inlineMultiModuleOverride.kt") public void testInlineMultiModuleOverride_1_2() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt"); - try { - doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental"); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental"); } @TestMetadata("inlineMultiModuleOverride.kt") public void testInlineMultiModuleOverride_1_3() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt"); - try { - doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines"); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines"); } @TestMetadata("inlineMultiModuleWithController.kt") diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index f5a5b57ea72..efb08cf742b 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -3422,6 +3422,29 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineUsedAsNoinline extends AbstractIrBlackBoxInlineCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInInlineUsedAsNoinline() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("inlineOnly.kt") + public void testInlineOnly() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt"); + } + + @TestMetadata("simpleNamed.kt") + public void testSimpleNamed() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index bbc017d6c05..c90645949f8 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3422,6 +3422,29 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineUsedAsNoinline extends AbstractIrCompileKotlinAgainstInlineKotlinTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInInlineUsedAsNoinline() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("inlineOnly.kt") + public void testInlineOnly() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt"); + } + + @TestMetadata("simpleNamed.kt") + public void testSimpleNamed() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 47edebd3d66..3b175a6277f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -7059,25 +7059,13 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { @TestMetadata("inlineMultiModuleOverride.kt") public void testInlineMultiModuleOverride_1_2() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt"); - try { - doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental"); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental"); } @TestMetadata("inlineMultiModuleOverride.kt") public void testInlineMultiModuleOverride_1_3() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt"); - try { - doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines"); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines"); } @TestMetadata("inlineMultiModuleWithController.kt") diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index dba9d993c50..92739631958 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -3422,6 +3422,29 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineUsedAsNoinline extends AbstractBlackBoxInlineCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInInlineUsedAsNoinline() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("inlineOnly.kt") + public void testInlineOnly() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt"); + } + + @TestMetadata("simpleNamed.kt") + public void testSimpleNamed() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 0579db9eb86..5d0144ed8c1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -253,6 +253,24 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { } } + @TestMetadata("compiler/testData/codegen/bytecodeListing/inline") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Inline extends AbstractBytecodeListingTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInInline() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing/inline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("simpleNamed.kt") + public void testSimpleNamed() throws Exception { + runTest("compiler/testData/codegen/bytecodeListing/inline/simpleNamed.kt"); + } + } + @TestMetadata("compiler/testData/codegen/bytecodeListing/inlineClasses") @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 ec6e5831a7f..d93d5f2374e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -3422,6 +3422,29 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi } } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineUsedAsNoinline extends AbstractCompileKotlinAgainstInlineKotlinTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInInlineUsedAsNoinline() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("inlineOnly.kt") + public void testInlineOnly() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/inlineOnly.kt"); + } + + @TestMetadata("simpleNamed.kt") + public void testSimpleNamed() throws Exception { + runTest("compiler/testData/codegen/boxInline/suspend/inlineUsedAsNoinline/simpleNamed.kt"); + } + } + @TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index db052ceec7b..411df2d12bf 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -7036,30 +7036,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class MultiModule extends AbstractLightAnalysisModeTest { - @TestMetadata("inlineMultiModuleOverride.kt") - public void ignoreInlineMultiModuleOverride_1_2() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt"); - try { - doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental"); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); - } - - @TestMetadata("inlineMultiModuleOverride.kt") - public void ignoreInlineMultiModuleOverride_1_3() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt"); - try { - doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines"); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); - } - private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -7080,6 +7056,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines"); } + @TestMetadata("inlineMultiModuleOverride.kt") + public void testInlineMultiModuleOverride_1_2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt"); + doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines.experimental"); + } + + @TestMetadata("inlineMultiModuleOverride.kt") + public void testInlineMultiModuleOverride_1_3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt"); + doTestWithCoroutinesPackageReplacement(fileName, "kotlin.coroutines"); + } + @TestMetadata("inlineMultiModuleWithController.kt") public void testInlineMultiModuleWithController_1_2() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleWithController.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt index 223613b5a3e..b9daccd2e8e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/annotations/annotationUtil.kt @@ -73,7 +73,7 @@ fun MemberDescriptor.isInlineOnlyOrReifiable(): Boolean = this is CallableMemberDescriptor && (isReifiable() || DescriptorUtils.getDirectMember(this).isReifiable() || isInlineOnly()) fun MemberDescriptor.isEffectivelyInlineOnly(): Boolean = - isInlineOnlyOrReifiable() || safeAs()?.let { it.isSuspend && it.isInline } == true + isInlineOnlyOrReifiable() || (this is FunctionDescriptor && this.isSuspend && this.valueParameters.any { it.isCrossinline }) fun MemberDescriptor.isInlineOnly(): Boolean { if (this !is FunctionDescriptor ||