Support crossinline suspend lambda as parameter of inline function

Use fake continuation instead of ALOAD 0 while inlining
Do not generate state machine for inner lambdas and inner objects,
which capture crossinline suspend lambda.

 #KT-19159: Fixed
This commit is contained in:
Ilmir Usmanov
2018-01-18 15:21:19 +03:00
parent 042ca55be7
commit 6854135077
80 changed files with 5214 additions and 144 deletions
+1
View File
@@ -53,6 +53,7 @@
<component name="SuppressABINotification"> <component name="SuppressABINotification">
<option name="modulesWithSuppressedNotConfigured"> <option name="modulesWithSuppressedNotConfigured">
<set> <set>
<option value="backend.src" />
<option value="kotlin-stdlib-common" /> <option value="kotlin-stdlib-common" />
<option value="kotlin-stdlib-js" /> <option value="kotlin-stdlib-js" />
<option value="kotlin-test-common" /> <option value="kotlin-test-common" />
@@ -2343,7 +2343,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@NotNull CallGenerator callGenerator, @NotNull CallGenerator callGenerator,
@NotNull ArgumentGenerator argumentGenerator @NotNull ArgumentGenerator argumentGenerator
) { ) {
boolean isSuspendNoInlineCall = CoroutineCodegenUtilKt.isSuspendNoInlineCall(resolvedCall); boolean isSuspendNoInlineCall = CoroutineCodegenUtilKt.isSuspendNoInlineCall(resolvedCall, this);
boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor; boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
if (!(callableMethod instanceof IntrinsicWithSpecialReceiver)) { if (!(callableMethod instanceof IntrinsicWithSpecialReceiver)) {
putReceiverAndInlineMarkerIfNeeded(callableMethod, resolvedCall, receiver, isSuspendNoInlineCall, isConstructor); putReceiverAndInlineMarkerIfNeeded(callableMethod, resolvedCall, receiver, isSuspendNoInlineCall, isConstructor);
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotated; import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget; import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl; import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl;
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature; import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature;
import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.JvmAbi;
@@ -61,10 +62,7 @@ import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Collection; import java.util.*;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny; import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny;
import static org.jetbrains.kotlin.codegen.AsmUtil.*; import static org.jetbrains.kotlin.codegen.AsmUtil.*;
@@ -642,6 +640,10 @@ public class FunctionCodegen {
mv.visitLabel(methodEnd); mv.visitLabel(methodEnd);
Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper); Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper);
if (functionDescriptor instanceof AnonymousFunctionDescriptor && functionDescriptor.isSuspend()) {
functionDescriptor = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(functionDescriptor, typeMapper.getBindingContext());
}
generateLocalVariableTable( generateLocalVariableTable(
mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind(), typeMapper, mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind(), typeMapper,
(functionFakeIndex >= 0 ? 1 : 0) + (lambdaFakeIndex >= 0 ? 1 : 0) (functionFakeIndex >= 0 ? 1 : 0) + (lambdaFakeIndex >= 0 ? 1 : 0)
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * 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.
* 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.
*/ */
package org.jetbrains.kotlin.codegen.binding; package org.jetbrains.kotlin.codegen.binding;
@@ -25,6 +14,7 @@ import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.ReflectionTypes; import org.jetbrains.kotlin.builtins.ReflectionTypes;
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor;
import org.jetbrains.kotlin.cfg.WhenChecker; import org.jetbrains.kotlin.cfg.WhenChecker;
import org.jetbrains.kotlin.codegen.*; import org.jetbrains.kotlin.codegen.*;
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
@@ -51,6 +41,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument; import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument; import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
import org.jetbrains.kotlin.resolve.constants.ConstantValue; import org.jetbrains.kotlin.resolve.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.constants.EnumValue; import org.jetbrains.kotlin.resolve.constants.EnumValue;
import org.jetbrains.kotlin.resolve.constants.NullValue; import org.jetbrains.kotlin.resolve.constants.NullValue;
@@ -314,8 +305,25 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
nameStack.push(name); nameStack.push(name);
if (CoroutineUtilKt.isSuspendLambda(functionDescriptor)) { if (CoroutineUtilKt.isSuspendLambda(functionDescriptor)) {
SimpleFunctionDescriptor jvmSuspendFunctionView =
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
(SimpleFunctionDescriptor) functionDescriptor
);
bindingTrace.record(
CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW,
functionDescriptor,
jvmSuspendFunctionView
);
closure.setSuspend(true); closure.setSuspend(true);
closure.setSuspendLambda(); closure.setSuspendLambda();
if (capturesCrossinlineSuspendLambda(functionLiteral)) {
bindingTrace.record(
CodegenBinding.CAPTURES_CROSSINLINE_SUSPEND_LAMBDA,
functionDescriptor,
true
);
}
} }
super.visitLambdaExpression(lambdaExpression); super.visitLambdaExpression(lambdaExpression);
@@ -323,6 +331,35 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
classStack.pop(); classStack.pop();
} }
// If inner lambda captures crossinline suspend lambda, it is unsafe to generate state machine for it.
private boolean capturesCrossinlineSuspendLambda(@NotNull PsiElement psiNode) {
PsiElement[] children = psiNode.getChildren();
boolean res = false;
for (PsiElement child : children) {
if (child instanceof KtCallElement) {
KtExpression callee = ((KtCallElement) child).getCalleeExpression();
Call call = bindingContext.get(CALL, callee);
ResolvedCall<?> resolvedCall = bindingContext.get(RESOLVED_CALL, call);
if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
VariableAsFunctionResolvedCall variableAsFunction = (VariableAsFunctionResolvedCall) resolvedCall;
VariableDescriptor variableDescriptor = variableAsFunction.getVariableCall().getResultingDescriptor();
CallableDescriptor callableDescriptor = ((ResolvedCall) variableAsFunction).getResultingDescriptor();
if (variableDescriptor instanceof ValueParameterDescriptor &&
((ValueParameterDescriptor) variableDescriptor).isCrossinline() &&
callableDescriptor instanceof FunctionDescriptor &&
((FunctionDescriptor) callableDescriptor).isSuspend()) {
FunctionDescriptor enclosingDescriptor =
bindingContext.get(ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
assert(enclosingDescriptor != null);
return true;
}
}
}
res = res || capturesCrossinlineSuspendLambda(child);
}
return res;
}
@Override @Override
public void visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression) { public void visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression) {
ResolvedCall<?> referencedFunction = CallUtilKt.getResolvedCall(expression.getCallableReference(), bindingContext); ResolvedCall<?> referencedFunction = CallUtilKt.getResolvedCall(expression.getCallableReference(), bindingContext);
@@ -537,6 +574,14 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
MutableClosure closure = recordClosure(classDescriptor, name); MutableClosure closure = recordClosure(classDescriptor, name);
closure.setSuspend(true); closure.setSuspend(true);
if (capturesCrossinlineSuspendLambda(function)) {
bindingTrace.record(
CodegenBinding.CAPTURES_CROSSINLINE_SUSPEND_LAMBDA,
functionDescriptor,
true
);
}
super.visitNamedFunction(function); super.visitNamedFunction(function);
if (nameForClassOrPackageMember != null) { if (nameForClassOrPackageMember != null) {
@@ -52,6 +52,9 @@ public class CodegenBinding {
public static final WritableSlice<FunctionDescriptor, FunctionDescriptor> SUSPEND_FUNCTION_TO_JVM_VIEW = public static final WritableSlice<FunctionDescriptor, FunctionDescriptor> SUSPEND_FUNCTION_TO_JVM_VIEW =
Slices.createSimpleSlice(); Slices.createSimpleSlice();
public static final WritableSlice<FunctionDescriptor, Boolean> CAPTURES_CROSSINLINE_SUSPEND_LAMBDA =
Slices.createSimpleSlice();
public static final WritableSlice<ValueParameterDescriptor, ValueParameterDescriptor> PARAMETER_SYNONYM = public static final WritableSlice<ValueParameterDescriptor, ValueParameterDescriptor> PARAMETER_SYNONYM =
Slices.createSimpleSlice(); Slices.createSimpleSlice();
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.codegen.context.PackageContext
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.codegen.inline.ReificationArgument import org.jetbrains.kotlin.codegen.inline.ReificationArgument
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
@@ -50,6 +51,11 @@ import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.util.Textifier
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.io.StringWriter
import java.io.PrintWriter
import java.util.* import java.util.*
fun generateIsCheck( fun generateIsCheck(
@@ -424,3 +430,13 @@ inline fun FrameMap.evaluateOnce(
leaveTemp(asType) leaveTemp(asType)
} }
} }
// Handy debugging routine. Print all instructions from methodNode.
fun MethodNode.textifyMethodNode(): String {
val text = Textifier()
val tmv = TraceMethodVisitor(text)
this.instructions.asSequence().forEach { it.accept(tmv) }
val sw = StringWriter()
text.print(PrintWriter(sw))
return "$sw"
}
@@ -25,7 +25,7 @@ class InlineLambdaContext(
contextKind: OwnerKind, contextKind: OwnerKind,
parentContext: CodegenContext<*>, parentContext: CodegenContext<*>,
closure: MutableClosure?, closure: MutableClosure?,
private val isCrossInline: Boolean, val isCrossInline: Boolean,
private val isPropertyReference: Boolean private val isPropertyReference: Boolean
) : MethodContext(functionDescriptor, contextKind, parentContext, closure, false) { ) : MethodContext(functionDescriptor, contextKind, parentContext, closure, false) {
@@ -6,8 +6,10 @@
package org.jetbrains.kotlin.codegen.coroutines package org.jetbrains.kotlin.codegen.coroutines
import com.intellij.util.ArrayUtil import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.CAPTURES_CROSSINLINE_SUSPEND_LAMBDA
import org.jetbrains.kotlin.codegen.context.ClosureContext import org.jetbrains.kotlin.codegen.context.ClosureContext
import org.jetbrains.kotlin.codegen.context.MethodContext import org.jetbrains.kotlin.codegen.context.MethodContext
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
@@ -127,7 +129,8 @@ class CoroutineCodegenForLambda private constructor(
element: KtElement, element: KtElement,
private val closureContext: ClosureContext, private val closureContext: ClosureContext,
classBuilder: ClassBuilder, classBuilder: ClassBuilder,
private val originalSuspendFunctionDescriptor: FunctionDescriptor private val originalSuspendFunctionDescriptor: FunctionDescriptor,
private val forInline: Boolean
) : AbstractCoroutineCodegen( ) : AbstractCoroutineCodegen(
outerExpressionCodegen, element, closureContext, classBuilder, outerExpressionCodegen, element, closureContext, classBuilder,
userDataForDoResume = mapOf(INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME to originalSuspendFunctionDescriptor) userDataForDoResume = mapOf(INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME to originalSuspendFunctionDescriptor)
@@ -300,13 +303,14 @@ class CoroutineCodegenForLambda private constructor(
object : FunctionGenerationStrategy.FunctionDefault(state, element as KtDeclarationWithBody) { object : FunctionGenerationStrategy.FunctionDefault(state, element as KtDeclarationWithBody) {
override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor { override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor {
if (forInline) return super.wrapMethodVisitor(mv, access, name, desc)
return CoroutineTransformerMethodVisitor( return CoroutineTransformerMethodVisitor(
mv, access, name, desc, null, null, mv, access, name, desc, null, null,
obtainClassBuilderForCoroutineState = { v }, obtainClassBuilderForCoroutineState = { v },
element = element, lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization, shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = v.thisName, containingClassInternalName = v.thisName,
isForNamedFunction = false isForNamedFunction = false
) )
} }
@@ -336,7 +340,9 @@ class CoroutineCodegenForLambda private constructor(
originalSuspendLambdaDescriptor, expressionCodegen, expressionCodegen.state.typeMapper originalSuspendLambdaDescriptor, expressionCodegen, expressionCodegen.state.typeMapper
), ),
classBuilder, classBuilder,
originalSuspendLambdaDescriptor originalSuspendLambdaDescriptor,
// Local suspend lambdas, which call crossinline suspend parameters of containing functions must be generated after inlining
expressionCodegen.bindingContext[CAPTURES_CROSSINLINE_SUSPEND_LAMBDA, originalSuspendLambdaDescriptor] == true
) )
} }
} }
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.codegen.coroutines package org.jetbrains.kotlin.codegen.coroutines
import com.intellij.util.containers.Stack import com.intellij.util.containers.Stack
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
@@ -28,7 +27,6 @@ import org.jetbrains.kotlin.codegen.optimization.common.*
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.utils.sure import org.jetbrains.kotlin.utils.sure
@@ -53,7 +51,7 @@ class CoroutineTransformerMethodVisitor(
obtainClassBuilderForCoroutineState: () -> ClassBuilder, obtainClassBuilderForCoroutineState: () -> ClassBuilder,
private val isForNamedFunction: Boolean, private val isForNamedFunction: Boolean,
private val shouldPreserveClassInitialization: Boolean, private val shouldPreserveClassInitialization: Boolean,
private val element: KtElement, private val lineNumber: Int,
// It's only matters for named functions, may differ from '!isStatic(access)' in case of DefaultImpls // It's only matters for named functions, may differ from '!isStatic(access)' in case of DefaultImpls
private val needDispatchReceiver: Boolean = false, private val needDispatchReceiver: Boolean = false,
// May differ from containingClassInternalName in case of DefaultImpls // May differ from containingClassInternalName in case of DefaultImpls
@@ -67,6 +65,8 @@ class CoroutineTransformerMethodVisitor(
private var exceptionIndex = if (isForNamedFunction) -1 else 2 private var exceptionIndex = if (isForNamedFunction) -1 else 2
override fun performTransformations(methodNode: MethodNode) { override fun performTransformations(methodNode: MethodNode) {
removeFakeContinuationConstructorCall(methodNode)
val suspensionPoints = collectSuspensionPoints(methodNode) val suspensionPoints = collectSuspensionPoints(methodNode)
// First instruction in the method node may change in case of named function // First instruction in the method node may change in case of named function
@@ -78,11 +78,7 @@ class CoroutineTransformerMethodVisitor(
ReturnUnitMethodTransformer.transform(containingClassInternalName, methodNode) ReturnUnitMethodTransformer.transform(containingClassInternalName, methodNode)
if (allSuspensionPointsAreTailCalls(containingClassInternalName, methodNode, suspensionPoints)) { if (allSuspensionPointsAreTailCalls(containingClassInternalName, methodNode, suspensionPoints)) {
continuationIndex = continuationIndex = getLastParameterIndex(methodNode.desc, methodNode.access)
if (isStatic(methodNode.access))
Type.getArgumentTypes(methodNode.desc).size - 1
else
Type.getArgumentTypes(methodNode.desc).size
replaceFakeContinuationsWithRealOnes(methodNode, continuationIndex) replaceFakeContinuationsWithRealOnes(methodNode, continuationIndex)
dropSuspensionMarkers(methodNode, suspensionPoints) dropSuspensionMarkers(methodNode, suspensionPoints)
@@ -125,7 +121,6 @@ class CoroutineTransformerMethodVisitor(
val startLabel = LabelNode() val startLabel = LabelNode()
val defaultLabel = LabelNode() val defaultLabel = LabelNode()
val tableSwitchLabel = LabelNode() val tableSwitchLabel = LabelNode()
val lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0
// tableswitch(this.label) // tableswitch(this.label)
insertBefore( insertBefore(
@@ -161,12 +156,15 @@ class CoroutineTransformerMethodVisitor(
methodNode.removeEmptyCatchBlocks() methodNode.removeEmptyCatchBlocks()
} }
private fun replaceFakeContinuationsWithRealOnes(methodNode: MethodNode, continuationIndex: Int) { private fun removeFakeContinuationConstructorCall(methodNode: MethodNode) {
val fakeContinuations = methodNode.instructions.asSequence().filter(::isFakeContinuationMarker) val seq = methodNode.instructions.asSequence()
for (fakeContinuation in fakeContinuations) { val first = seq.firstOrNull(::isBeforeFakeContinuationConstructorCallMarker)?.previous ?: return
methodNode.instructions.removeAll(listOf(fakeContinuation.previous.previous, fakeContinuation.previous)) val last = seq.firstOrNull(::isAfterFakeContinuationConstructorCallMarker).sure {
methodNode.instructions.set(fakeContinuation, VarInsnNode(Opcodes.ALOAD, continuationIndex)) "BeforeFakeContinuationConstructorCallMarker without AfterFakeContinuationConstructorCallMarker"
} }
val toRemove = InsnSequence(first, last).toList()
methodNode.instructions.removeAll(toRemove)
methodNode.instructions.set(last, InsnNode(Opcodes.ACONST_NULL))
} }
private fun createInsnForReadingLabel() = private fun createInsnForReadingLabel() =
@@ -285,30 +283,13 @@ class CoroutineTransformerMethodVisitor(
visitLabel(createStateInstance) visitLabel(createStateInstance)
anew(objectTypeForState) generateContinuationConstructorCall(
dup() objectTypeForState,
methodNode,
val parameterTypesAndIndices = needDispatchReceiver,
getParameterTypesIndicesForCoroutineConstructor( internalNameForDispatchReceiver,
methodNode.desc, containingClassInternalName,
methodNode.access, classBuilderForCoroutineState
needDispatchReceiver, internalNameForDispatchReceiver ?: containingClassInternalName
)
for ((type, index) in parameterTypesAndIndices) {
load(index, type)
}
invokespecial(
classBuilderForCoroutineState.thisName,
"<init>",
Type.getMethodDescriptor(
Type.VOID_TYPE,
*getParameterTypesForCoroutineConstructor(
methodNode.desc, needDispatchReceiver,
internalNameForDispatchReceiver ?: containingClassInternalName
)
),
false
) )
visitVarInsn(Opcodes.ASTORE, continuationIndex) visitVarInsn(Opcodes.ASTORE, continuationIndex)
@@ -501,7 +482,7 @@ class CoroutineTransformerMethodVisitor(
): LabelNode { ): LabelNode {
val continuationLabel = LabelNode() val continuationLabel = LabelNode()
val continuationLabelAfterLoadedResult = LabelNode() val continuationLabelAfterLoadedResult = LabelNode()
val suspendElementLineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0 val suspendElementLineNumber = lineNumber
val nextLineNumberNode = suspension.suspensionCallEnd.findNextOrNull { it is LineNumberNode } as? LineNumberNode val nextLineNumberNode = suspension.suspensionCallEnd.findNextOrNull { it is LineNumberNode } as? LineNumberNode
with(methodNode.instructions) { with(methodNode.instructions) {
// Save state // Save state
@@ -616,6 +597,41 @@ class CoroutineTransformerMethodVisitor(
} }
} }
internal fun InstructionAdapter.generateContinuationConstructorCall(
objectTypeForState: Type?,
methodNode: MethodNode,
needDispatchReceiver: Boolean,
internalNameForDispatchReceiver: String?,
containingClassInternalName: String,
classBuilderForCoroutineState: ClassBuilder
) {
anew(objectTypeForState)
dup()
val parameterTypesAndIndices =
getParameterTypesIndicesForCoroutineConstructor(
methodNode.desc,
methodNode.access,
needDispatchReceiver, internalNameForDispatchReceiver ?: containingClassInternalName
)
for ((type, index) in parameterTypesAndIndices) {
load(index, type)
}
invokespecial(
classBuilderForCoroutineState.thisName,
"<init>",
Type.getMethodDescriptor(
Type.VOID_TYPE,
*getParameterTypesForCoroutineConstructor(
methodNode.desc, needDispatchReceiver,
internalNameForDispatchReceiver ?: containingClassInternalName
)
),
false
)
}
private fun InstructionAdapter.generateResumeWithExceptionCheck(exceptionIndex: Int) { private fun InstructionAdapter.generateResumeWithExceptionCheck(exceptionIndex: Int) {
// Check if resumeWithException has been called // Check if resumeWithException has been called
load(exceptionIndex, AsmTypes.OBJECT_TYPE) load(exceptionIndex, AsmTypes.OBJECT_TYPE)
@@ -803,3 +819,11 @@ private fun AbstractInsnNode?.isInvisibleInDebugVarInsn(methodNode: MethodNode):
private val SAFE_OPCODES = private val SAFE_OPCODES =
((Opcodes.DUP..Opcodes.DUP2_X2) + Opcodes.NOP + Opcodes.POP + Opcodes.POP2 + (Opcodes.IFEQ..Opcodes.GOTO)).toSet() ((Opcodes.DUP..Opcodes.DUP2_X2) + Opcodes.NOP + Opcodes.POP + Opcodes.POP2 + (Opcodes.IFEQ..Opcodes.GOTO)).toSet()
internal fun replaceFakeContinuationsWithRealOnes(methodNode: MethodNode, continuationIndex: Int) {
val fakeContinuations = methodNode.instructions.asSequence().filter(::isFakeContinuationMarker).toList()
for (fakeContinuation in fakeContinuations) {
methodNode.instructions.removeAll(listOf(fakeContinuation.previous.previous, fakeContinuation.previous))
methodNode.instructions.set(fakeContinuation, VarInsnNode(Opcodes.ALOAD, continuationIndex))
}
}
@@ -16,9 +16,13 @@
package org.jetbrains.kotlin.codegen.coroutines package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy import org.jetbrains.kotlin.codegen.FunctionGenerationStrategy
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.inline.addFakeContinuationConstructorCallMarker
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode import org.jetbrains.kotlin.config.JVMConstructorCallNormalizationMode
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -30,6 +34,8 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class SuspendFunctionGenerationStrategy( class SuspendFunctionGenerationStrategy(
state: GenerationState, state: GenerationState,
@@ -39,7 +45,6 @@ class SuspendFunctionGenerationStrategy(
private val constructorCallNormalizationMode: JVMConstructorCallNormalizationMode private val constructorCallNormalizationMode: JVMConstructorCallNormalizationMode
) : FunctionGenerationStrategy.CodegenBased(state) { ) : FunctionGenerationStrategy.CodegenBased(state) {
private lateinit var transformer: CoroutineTransformerMethodVisitor
private lateinit var codegen: ExpressionCodegen private lateinit var codegen: ExpressionCodegen
private val classBuilderForCoroutineState by lazy { private val classBuilderForCoroutineState by lazy {
@@ -57,16 +62,22 @@ class SuspendFunctionGenerationStrategy(
override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor { override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor {
if (access and Opcodes.ACC_ABSTRACT != 0) return mv if (access and Opcodes.ACC_ABSTRACT != 0) return mv
return CoroutineTransformerMethodVisitor( if (state.bindingContext[CodegenBinding.CAPTURES_CROSSINLINE_SUSPEND_LAMBDA, originalSuspendDescriptor] == true) {
mv, access, name, desc, null, null, containingClassInternalName, this::classBuilderForCoroutineState, return AddConstructorCallForCoroutineRegeneration(
isForNamedFunction = true, mv, access, name, desc, null, null, this::classBuilderForCoroutineState,
element = declaration, containingClassInternalName,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization, originalSuspendDescriptor.dispatchReceiverParameter != null,
needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null, containingClassInternalNameOrNull()
internalNameForDispatchReceiver = containingClassInternalNameOrNull() )
).also {
transformer = it
} }
return CoroutineTransformerMethodVisitor(
mv, access, name, desc, null, null, containingClassInternalName, this::classBuilderForCoroutineState,
isForNamedFunction = true,
lineNumber = CodegenUtil.getLineNumberForElement(declaration, false) ?: 0,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null,
internalNameForDispatchReceiver = containingClassInternalNameOrNull()
)
} }
private fun containingClassInternalNameOrNull() = private fun containingClassInternalNameOrNull() =
@@ -76,4 +87,39 @@ class SuspendFunctionGenerationStrategy(
this.codegen = codegen this.codegen = codegen
codegen.returnExpression(declaration.bodyExpression ?: error("Function has no body: " + declaration.getElementTextWithContext())) codegen.returnExpression(declaration.bodyExpression ?: error("Function has no body: " + declaration.getElementTextWithContext()))
} }
// When we generate named suspend function for the use as inline site, we do not generate state machine.
// So, there will be no way to remember the name of generated continuation in such case.
// In order to keep generated continuation for named suspend function, we just generate construction call, which is going to be
// removed during inlining.
// The continuation itself will be regenerated and used as a container for the coroutine's locals.
private class AddConstructorCallForCoroutineRegeneration(
delegate: MethodVisitor,
access: Int,
name: String,
desc: String,
signature: String?,
exceptions: Array<out String>?,
obtainClassBuilderForCoroutineState: () -> ClassBuilder,
private val containingClassInternalName: String,
private val needDispatchReceiver: Boolean,
private val internalNameForDispatchReceiver: String?
) : TransformationMethodVisitor(delegate, access, name, desc, signature, exceptions) {
private val classBuilderForCoroutineState: ClassBuilder by lazy(obtainClassBuilderForCoroutineState)
override fun performTransformations(methodNode: MethodNode) {
val objectTypeForState = Type.getObjectType(classBuilderForCoroutineState.thisName)
methodNode.instructions.insert(withInstructionAdapter {
addFakeContinuationConstructorCallMarker(this, true)
generateContinuationConstructorCall(
objectTypeForState,
methodNode,
needDispatchReceiver,
internalNameForDispatchReceiver,
containingClassInternalName,
classBuilderForCoroutineState
)
addFakeContinuationConstructorCallMarker(this, false)
})
}
}
} }
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.coroutines
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.inline.addFakeContinuationMarker import org.jetbrains.kotlin.codegen.inline.addFakeContinuationMarker
@@ -175,13 +176,18 @@ private fun NewResolvedCallImpl<VariableDescriptor>.asDummyOldResolvedCall(bindi
) )
} }
fun ResolvedCall<*>.isSuspendNoInlineCall(): Boolean { fun ResolvedCall<*>.isSuspendNoInlineCall(codegen: ExpressionCodegen): Boolean {
val isCrossinline = var isCrossinline = false
safeAs<VariableAsFunctionResolvedCall>()?.variableCall?.resultingDescriptor?.safeAs<ValueParameterDescriptor>()?.isCrossinline var isInlineLambda = false
?: false if (this is VariableAsFunctionResolvedCall) {
variableCall.resultingDescriptor.safeAs<ValueParameterDescriptor>()?.let {
isCrossinline = it.isCrossinline
isInlineLambda = !isCrossinline && !it.isNoinline && codegen.context.functionDescriptor.isInline
}
}
return resultingDescriptor.safeAs<FunctionDescriptor>() return resultingDescriptor.safeAs<FunctionDescriptor>()
?.let { ?.let {
val inline = it.isInline || isCrossinline val inline = it.isInline || isCrossinline || isInlineLambda
it.isSuspend && (!inline || it.isBuiltInSuspendCoroutineOrReturnInJvm() || it.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm()) it.isSuspend && (!inline || it.isBuiltInSuspendCoroutineOrReturnInJvm() || it.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm())
} == true } == true
} }
@@ -21,15 +21,17 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ClassBuilder import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.coroutines.COROUTINE_IMPL_ASM_TYPE import org.jetbrains.kotlin.codegen.coroutines.COROUTINE_IMPL_ASM_TYPE
import org.jetbrains.kotlin.codegen.coroutines.CoroutineTransformerMethodVisitor
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable
import org.jetbrains.kotlin.codegen.writeKotlinMetadata import org.jetbrains.kotlin.codegen.writeKotlinMetadata
import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor
import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
@@ -41,7 +43,8 @@ import java.util.*
class AnonymousObjectTransformer( class AnonymousObjectTransformer(
transformationInfo: AnonymousObjectTransformationInfo, transformationInfo: AnonymousObjectTransformationInfo,
private val inliningContext: InliningContext, private val inliningContext: InliningContext,
private val isSameModule: Boolean private val isSameModule: Boolean,
private val continuationClassName: String?
) : ObjectTransformer<AnonymousObjectTransformationInfo>(transformationInfo, inliningContext.state) { ) : ObjectTransformer<AnonymousObjectTransformationInfo>(transformationInfo, inliningContext.state) {
private val oldObjectType = Type.getObjectType(transformationInfo.oldClassName) private val oldObjectType = Type.getObjectType(transformationInfo.oldClassName)
@@ -138,12 +141,39 @@ class AnonymousObjectTransformer(
val additionalFakeParams = extractParametersMappingAndPatchConstructor( val additionalFakeParams = extractParametersMappingAndPatchConstructor(
constructor!!, allCapturedParamBuilder, constructorParamBuilder,transformationInfo, parentRemapper constructor!!, allCapturedParamBuilder, constructorParamBuilder,transformationInfo, parentRemapper
) )
val capturesCrossinlineSuspend = (!inliningContext.isInliningLambda || inliningContext.isContinuation) &&
inliningContext.expressionMap.values.any { lambda ->
lambda is PsiExpressionLambda && lambda.isCrossInline && lambda.invokeMethodDescriptor.isSuspend
}
val deferringMethods = ArrayList<DeferredMethodVisitor>() val deferringMethods = ArrayList<DeferredMethodVisitor>()
generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, parentRemapper, additionalFakeParams) generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, parentRemapper, additionalFakeParams)
val isLambdaAlreadyGeneratedAndNotGoingToBeInlined = transformationInfo.oldClassName.contains("\$\$special\$\$inlined")
val hasLambdasToInline =
((parentRemapper is RegeneratedLambdaFieldRemapper) && parentRemapper.recapturedLambdas.isNotEmpty()) || transformationInfo.capturedLambdasToInline.isNotEmpty()
for (next in methodsToTransform) { for (next in methodsToTransform) {
val deferringVisitor = newMethod(classBuilder, next) // Generate state machine for
// 1) doResume method of suspend lambda
// 2) Suspend named function
// Iff it captures crossinline suspend lambda
val generateStateMachineForLambda =
next.name == "doResume" && capturesCrossinlineSuspend && inliningContext.isContinuation &&
!isLambdaAlreadyGeneratedAndNotGoingToBeInlined && hasLambdasToInline
val continuationClassName = findFakeContinuationConstructorClassName(next)
val generateStateMachineForNamedFunction =
capturesCrossinlineSuspend && !inliningContext.isContinuation && continuationClassName != null
val deferringVisitor =
when {
generateStateMachineForLambda -> newStateMachineForLambda(classBuilder, next)
generateStateMachineForNamedFunction -> newStateMachineForNamedFunction(classBuilder, next, continuationClassName!!)
else -> newMethod(classBuilder, next)
}
val funResult = inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false) val funResult = inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false)
val returnType = Type.getReturnType(next.desc) val returnType = Type.getReturnType(next.desc)
@@ -160,6 +190,21 @@ class AnonymousObjectTransformer(
deferringMethods.forEach { method -> deferringMethods.forEach { method ->
removeFinallyMarkers(method.intermediate) removeFinallyMarkers(method.intermediate)
method.visitEnd() method.visitEnd()
// During regeneration of named suspend functions, which capture crossinline suspend lambda, we need to spill the variables
// into continuation object.
// In order to do this, we reuse class builder, which regenerates continuation object.
if (capturesCrossinlineSuspend &&
!inliningContext.isContinuation &&
inliningContext is RegeneratedClassContext
) {
val continuationClassName = findFakeContinuationConstructorClassName(method.intermediate)
if (continuationClassName != null) {
inliningContext.continuationBuilders
.remove(continuationClassName)
?.let(ClassBuilder::done)
}
}
} }
SourceMapper.flushToClassBuilder(sourceMapper, classBuilder) SourceMapper.flushToClassBuilder(sourceMapper, classBuilder)
@@ -177,7 +222,12 @@ class AnonymousObjectTransformer(
writeOuterInfo(visitor) writeOuterInfo(visitor)
classBuilder.done() if (continuationClassName == transformationInfo.oldClassName) {
assert(inliningContext.parent?.parent is RegeneratedClassContext)
(inliningContext.parent?.parent as RegeneratedClassContext).continuationBuilders[continuationClassName] = classBuilder
} else {
classBuilder.done()
}
return transformationResult return transformationResult
} }
@@ -390,6 +440,55 @@ class AnonymousObjectTransformer(
} }
} }
private fun newStateMachineForLambda(builder: ClassBuilder, original: MethodNode): DeferredMethodVisitor {
return DeferredMethodVisitor(
MethodNode(
original.access, original.name, original.desc, original.signature,
ArrayUtil.toStringArray(original.exceptions)
)
) {
CoroutineTransformerMethodVisitor(
builder.newMethod(
NO_ORIGIN, original.access, original.name, original.desc, original.signature,
ArrayUtil.toStringArray(original.exceptions)
), original.access, original.name, original.desc, null, null,
obtainClassBuilderForCoroutineState = { builder },
lineNumber = 0, // <- TODO
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = builder.thisName,
isForNamedFunction = false
)
}
}
private fun newStateMachineForNamedFunction(
builder: ClassBuilder,
original: MethodNode,
continuationClassName: String
): DeferredMethodVisitor {
assert(inliningContext is RegeneratedClassContext)
return DeferredMethodVisitor(
MethodNode(
original.access, original.name, original.desc, original.signature,
ArrayUtil.toStringArray(original.exceptions)
)
) {
CoroutineTransformerMethodVisitor(
builder.newMethod(
NO_ORIGIN, original.access, original.name, original.desc, original.signature,
ArrayUtil.toStringArray(original.exceptions)
), original.access, original.name, original.desc, null, null,
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
lineNumber = 0, // <- TODO
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = builder.thisName,
isForNamedFunction = true,
needDispatchReceiver = true,
internalNameForDispatchReceiver = builder.thisName
)
}
}
private fun extractParametersMappingAndPatchConstructor( private fun extractParametersMappingAndPatchConstructor(
constructor: MethodNode, constructor: MethodNode,
capturedParamBuilder: ParametersBuilder, capturedParamBuilder: ParametersBuilder,
@@ -535,3 +634,10 @@ class AnonymousObjectTransformer(
private fun isFirstDeclSiteLambdaFieldRemapper(parentRemapper: FieldRemapper): Boolean = private fun isFirstDeclSiteLambdaFieldRemapper(parentRemapper: FieldRemapper): Boolean =
parentRemapper !is RegeneratedLambdaFieldRemapper && parentRemapper !is InlinedLambdaRemapper parentRemapper !is RegeneratedLambdaFieldRemapper && parentRemapper !is InlinedLambdaRemapper
} }
internal fun findFakeContinuationConstructorClassName(node: MethodNode): String? {
val marker = node.instructions.asSequence().firstOrNull(::isBeforeFakeContinuationConstructorCallMarker) ?: return null
val new = marker.next
assert(new?.opcode == Opcodes.NEW)
return (new as TypeInsnNode).desc
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen.inline package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.ClassBuilder
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
@@ -41,11 +42,13 @@ class RegeneratedClassContext(
override val callSiteInfo: InlineCallSiteInfo override val callSiteInfo: InlineCallSiteInfo
) : InliningContext( ) : InliningContext(
parent, expressionMap, state, nameGenerator, typeRemapper, lambdaInfo, true parent, expressionMap, state, nameGenerator, typeRemapper, lambdaInfo, true
) ) {
val continuationBuilders: MutableMap<String, ClassBuilder> = hashMapOf()
}
open class InliningContext( open class InliningContext(
val parent: InliningContext?, val parent: InliningContext?,
private val expressionMap: Map<Int, LambdaInfo>, val expressionMap: Map<Int, LambdaInfo>,
val state: GenerationState, val state: GenerationState,
val nameGenerator: NameGenerator, val nameGenerator: NameGenerator,
val typeRemapper: TypeRemapper, val typeRemapper: TypeRemapper,
@@ -55,7 +58,7 @@ open class InliningContext(
val isInliningLambda = lambdaInfo != null val isInliningLambda = lambdaInfo != null
val internalNameToAnonymousObjectTransformationInfo = hashMapOf<String, AnonymousObjectTransformationInfo>() private val internalNameToAnonymousObjectTransformationInfo = hashMapOf<String, AnonymousObjectTransformationInfo>()
var isContinuation: Boolean = false var isContinuation: Boolean = false
@@ -64,6 +67,14 @@ open class InliningContext(
val root: RootInliningContext val root: RootInliningContext
get() = if (isRoot) this as RootInliningContext else parent!!.root get() = if (isRoot) this as RootInliningContext else parent!!.root
fun findAnonymousObjectTransformationInfo(internalName: String, searchInParent: Boolean = true): AnonymousObjectTransformationInfo? =
internalNameToAnonymousObjectTransformationInfo[internalName]
?: if (searchInParent) parent?.findAnonymousObjectTransformationInfo(internalName, searchInParent) else null
fun recordIfNotPresent(internalName: String, info: AnonymousObjectTransformationInfo) {
internalNameToAnonymousObjectTransformationInfo.putIfAbsent(internalName, info)
}
fun subInlineLambda(lambdaInfo: LambdaInfo): InliningContext = fun subInlineLambda(lambdaInfo: LambdaInfo): InliningContext =
subInline( subInline(
nameGenerator.subGenerator("lambda"), nameGenerator.subGenerator("lambda"),
@@ -104,8 +115,4 @@ open class InliningContext(
get() { get() {
return parent!!.callSiteInfo return parent!!.callSiteInfo
} }
fun findAnonymousObjectTransformationInfo(internalName: String): AnonymousObjectTransformationInfo? {
return root.internalNameToAnonymousObjectTransformationInfo[internalName]
}
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * 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.
* 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.
*/ */
package org.jetbrains.kotlin.codegen.inline package org.jetbrains.kotlin.codegen.inline
@@ -9,18 +9,23 @@ import org.jetbrains.kotlin.backend.jvm.codegen.IrExpressionLambda
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ClosureCodegen import org.jetbrains.kotlin.codegen.ClosureCodegen
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_ASM_TYPE
import org.jetbrains.kotlin.codegen.coroutines.replaceFakeContinuationsWithRealOnes
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.fixStack.peek import org.jetbrains.kotlin.codegen.optimization.fixStack.peek
import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.resolve.isInlineClassType import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.SmartSet import org.jetbrains.kotlin.utils.SmartSet
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
@@ -159,7 +164,11 @@ class MethodInliner(
currentTypeMapping, currentTypeMapping,
inlineCallSiteInfo inlineCallSiteInfo
) )
val transformer = transformationInfo!!.createTransformer(childInliningContext, isSameModule) val transformer = transformationInfo!!.createTransformer(
childInliningContext,
isSameModule,
findFakeContinuationConstructorClassName(node)
)
val transformResult = transformer.doTransform(nodeRemapper) val transformResult = transformer.doTransform(nodeRemapper)
result.merge(transformResult) result.merge(transformResult)
@@ -308,7 +317,7 @@ class MethodInliner(
//TODO: add new inner class also for other contexts //TODO: add new inner class also for other contexts
if (inliningContext.parent is RegeneratedClassContext) { if (inliningContext.parent is RegeneratedClassContext) {
inliningContext.parent.typeRemapper.addAdditionalMappings( inliningContext.parent.typeRemapper.addAdditionalMappings(
transformationInfo!!.oldClassName, transformationInfo!!.newClassName transformationInfo!!.oldClassName, transformationInfo!!.newClassName
) )
} }
@@ -319,7 +328,7 @@ class MethodInliner(
} }
} }
else if ((!inliningContext.isInliningLambda || isDefaultLambdaWithReification(inliningContext.lambdaInfo!!)) && else if ((!inliningContext.isInliningLambda || isDefaultLambdaWithReification(inliningContext.lambdaInfo!!)) &&
ReifiedTypeInliner.isNeedClassReificationMarker(MethodInsnNode(opcode, owner, name, desc, false))) { ReifiedTypeInliner.isNeedClassReificationMarker(MethodInsnNode(opcode, owner, name, desc, false))) {
//we shouldn't process here content of inlining lambda it should be reified at external level except default lambdas //we shouldn't process here content of inlining lambda it should be reified at external level except default lambdas
} }
else { else {
@@ -443,6 +452,8 @@ class MethodInliner(
preprocessNodeBeforeInline(processingNode, labelOwner) preprocessNodeBeforeInline(processingNode, labelOwner)
replaceContinuationAccessesWithFakeContinuationsIfNeeded(processingNode)
val sources = analyzeMethodNodeBeforeInline(processingNode) val sources = analyzeMethodNodeBeforeInline(processingNode)
val toDelete = SmartSet.create<AbstractInsnNode>() val toDelete = SmartSet.create<AbstractInsnNode>()
@@ -584,6 +595,67 @@ class MethodInliner(
return processingNode return processingNode
} }
// Replace ALOAD 0
// with
// ICONST fakeContinuationMarker
// INVOKESTATIC InlineMarker.mark
// ACONST_NULL
// iff this ALOAD 0 is continuation and one of the following conditions is met
// 1) it is passed as the last parameter to suspending function
// 2) it is ASTORE'd right after
// 3) it is passed to invoke of lambda
private fun replaceContinuationAccessesWithFakeContinuationsIfNeeded(processingNode: MethodNode) {
val lambdaInfo = inliningContext.lambdaInfo ?: return
if (!lambdaInfo.invokeMethodDescriptor.isSuspend) return
val aload0s = processingNode.instructions.asSequence().filter { it.opcode == Opcodes.ALOAD && it.safeAs<VarInsnNode>()?.`var` == 0 }
// Expected pattern here:
// ALOAD 0
// ICONST_0
// INVOKESTATIC InlineMarker.mark
// INVOKE* suspendingFunction(..., Continuation;)Ljava/lang/Object;
val continuationAsParameterAload0s =
aload0s.filter { it.next?.next?.let(::isBeforeSuspendMarker) == true && isSuspendCall(it.next?.next?.next) }
replaceContinuationsWithFakeOnes(continuationAsParameterAload0s, processingNode)
// Expected pattern here:
// ALOAD 0
// ASTORE N
// This pattern may occur after multiple inlines
val continuationToStoreAload0s = aload0s.filter { it.next?.opcode == Opcodes.ASTORE }
replaceContinuationsWithFakeOnes(continuationToStoreAload0s, processingNode)
// Expected pattern here:
// ALOAD 0
// INVOKEINTERFACE kotlin/jvm/functions/FunctionN.invoke (...,Ljava/lang/Object;)Ljava/lang/Object;
val continuationAsLambdaParameterAload0s = aload0s.filter { isLambdaCall(it.next) }
replaceContinuationsWithFakeOnes(continuationAsLambdaParameterAload0s, processingNode)
}
private fun isLambdaCall(invoke: AbstractInsnNode?): Boolean {
if (invoke?.opcode != Opcodes.INVOKEINTERFACE) return false
invoke as MethodInsnNode
if (!invoke.owner.startsWith("kotlin/jvm/functions/Function")) return false
if (invoke.name != "invoke") return false
if (Type.getReturnType(invoke.desc) != OBJECT_TYPE) return false
return Type.getArgumentTypes(invoke.desc).let { it.isNotEmpty() && it.last() == OBJECT_TYPE }
}
private fun replaceContinuationsWithFakeOnes(
continuations: Sequence<AbstractInsnNode>,
node: MethodNode
) {
for (toReplace in continuations) {
insertNodeBefore(createFakeContinuationMethodNodeForInline(), node, toReplace)
node.instructions.remove(toReplace)
}
}
private fun isSuspendCall(invoke: AbstractInsnNode?): Boolean {
if (invoke !is MethodInsnNode) return false
// We can't have suspending constructors.
assert(invoke.opcode != Opcodes.INVOKESPECIAL)
if (Type.getReturnType(invoke.desc) != OBJECT_TYPE) return false
return Type.getArgumentTypes(invoke.desc).let { it.isNotEmpty() && it.last() == CONTINUATION_ASM_TYPE }
}
private fun preprocessNodeBeforeInline(node: MethodNode, labelOwner: LabelOwner) { private fun preprocessNodeBeforeInline(node: MethodNode, labelOwner: LabelOwner) {
try { try {
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node) FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
@@ -635,7 +707,6 @@ class MethodInliner(
needReification: Boolean, needReification: Boolean,
capturesAnonymousObjectThatMustBeRegenerated: Boolean capturesAnonymousObjectThatMustBeRegenerated: Boolean
): AnonymousObjectTransformationInfo { ): AnonymousObjectTransformationInfo {
val memoizeAnonymousObject = inliningContext.findAnonymousObjectTransformationInfo(anonymousType) == null
val info = AnonymousObjectTransformationInfo( val info = AnonymousObjectTransformationInfo(
anonymousType, needReification, lambdaMapping, anonymousType, needReification, lambdaMapping,
@@ -647,8 +718,16 @@ class MethodInliner(
capturesAnonymousObjectThatMustBeRegenerated capturesAnonymousObjectThatMustBeRegenerated
) )
if (memoizeAnonymousObject) { val memoizeAnonymousObject = inliningContext.findAnonymousObjectTransformationInfo(anonymousType)
inliningContext.root.internalNameToAnonymousObjectTransformationInfo.put(anonymousType, info) if (memoizeAnonymousObject == null ||
//anonymous object could be inlined in several context without transformation (keeps same class name)
// and on further inlining such code some of such cases would be transformed and some not,
// so we should distinguish one classes from another more clearly
!memoizeAnonymousObject.shouldRegenerate(isSameModule) &&
info.shouldRegenerate(isSameModule)
) {
inliningContext.recordIfNotPresent(anonymousType, info)
} }
return info return info
} }
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2015 JetBrains s.r.o. * 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.
* 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.
*/ */
package org.jetbrains.kotlin.codegen.inline package org.jetbrains.kotlin.codegen.inline
@@ -43,7 +43,7 @@ class SamWrapperTransformationInfo(override val oldClassName: String, private va
override fun canRemoveAfterTransformation() = false override fun canRemoveAfterTransformation() = false
override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean) = override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean, continuationClassName: String?) =
SamWrapperTransformer(this, inliningContext) SamWrapperTransformer(this, inliningContext)
} }
@@ -34,7 +34,7 @@ interface TransformationInfo {
fun canRemoveAfterTransformation(): Boolean fun canRemoveAfterTransformation(): Boolean
fun createTransformer(inliningContext: InliningContext, sameModule: Boolean): ObjectTransformer<*> fun createTransformer(inliningContext: InliningContext, sameModule: Boolean, continuationClassName: String?): ObjectTransformer<*>
} }
class WhenMappingTransformationInfo( class WhenMappingTransformationInfo(
@@ -52,7 +52,7 @@ class WhenMappingTransformationInfo(
override fun canRemoveAfterTransformation(): Boolean = true override fun canRemoveAfterTransformation(): Boolean = true
override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean): ObjectTransformer<*> = override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean, continuationClassName: String?): ObjectTransformer<*> =
WhenMappingTransformer(this, inliningContext) WhenMappingTransformer(this, inliningContext)
companion object { companion object {
@@ -103,6 +103,10 @@ class AnonymousObjectTransformationInfo internal constructor(
return !isStaticOrigin return !isStaticOrigin
} }
override fun createTransformer(inliningContext: InliningContext, sameModule: Boolean): ObjectTransformer<*> = override fun createTransformer(
AnonymousObjectTransformer(this, inliningContext, sameModule) inliningContext: InliningContext,
sameModule: Boolean,
continuationClassName: String?
): ObjectTransformer<*> =
AnonymousObjectTransformer(this, inliningContext, sameModule, continuationClassName)
} }
@@ -84,6 +84,8 @@ private const val INLINE_MARKER_BEFORE_SUSPEND_ID = 0
private const val INLINE_MARKER_AFTER_SUSPEND_ID = 1 private const val INLINE_MARKER_AFTER_SUSPEND_ID = 1
private const val INLINE_MARKER_RETURNS_UNIT = 2 private const val INLINE_MARKER_RETURNS_UNIT = 2
private const val INLINE_MARKER_FAKE_CONTINUATION = 3 private const val INLINE_MARKER_FAKE_CONTINUATION = 3
private const val INLINE_MARKER_BEFORE_FAKE_CONTINUATION_CONSTRUCTOR_CALL = 4
private const val INLINE_MARKER_AFTER_FAKE_CONTINUATION_CONSTRUCTOR_CALL = 5
private val INTRINSIC_ARRAY_CONSTRUCTOR_TYPE = AsmUtil.asmTypeByClassId(classId) private val INTRINSIC_ARRAY_CONSTRUCTOR_TYPE = AsmUtil.asmTypeByClassId(classId)
internal fun getMethodNode( internal fun getMethodNode(
@@ -295,6 +297,13 @@ internal fun insertNodeBefore(from: MethodNode, to: MethodNode, beforeNode: Abst
internal fun createEmptyMethodNode() = MethodNode(API, 0, "fake", "()V", null, null) internal fun createEmptyMethodNode() = MethodNode(API, 0, "fake", "()V", null, null)
internal fun createFakeContinuationMethodNodeForInline(): MethodNode {
val methodNode = createEmptyMethodNode()
val v = InstructionAdapter(methodNode)
addFakeContinuationMarker(v)
return methodNode
}
internal fun firstLabelInChain(node: LabelNode): LabelNode { internal fun firstLabelInChain(node: LabelNode): LabelNode {
var curNode = node var curNode = node
while (curNode.previous is LabelNode) { while (curNode.previous is LabelNode) {
@@ -425,6 +434,15 @@ internal fun addSuspendMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
) )
} }
internal fun addFakeContinuationConstructorCallMarker(v: InstructionAdapter, isStartNotEnd: Boolean) {
v.iconst(if (isStartNotEnd) INLINE_MARKER_BEFORE_FAKE_CONTINUATION_CONSTRUCTOR_CALL else INLINE_MARKER_AFTER_FAKE_CONTINUATION_CONSTRUCTOR_CALL)
v.visitMethodInsn(
Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME,
"mark",
"(I)V", false
)
}
private fun addReturnsUnitMarker(v: InstructionAdapter) { private fun addReturnsUnitMarker(v: InstructionAdapter) {
v.iconst(INLINE_MARKER_RETURNS_UNIT) v.iconst(INLINE_MARKER_RETURNS_UNIT)
v.visitMethodInsn( v.visitMethodInsn(
@@ -454,6 +472,10 @@ internal fun isAfterSuspendMarker(insn: AbstractInsnNode) = isSuspendMarker(insn
internal fun isReturnsUnitMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_RETURNS_UNIT) internal fun isReturnsUnitMarker(insn: AbstractInsnNode) = isSuspendMarker(insn, INLINE_MARKER_RETURNS_UNIT)
internal fun isFakeContinuationMarker(insn: AbstractInsnNode) = internal fun isFakeContinuationMarker(insn: AbstractInsnNode) =
insn.previous != null && isSuspendMarker(insn.previous, INLINE_MARKER_FAKE_CONTINUATION) && insn.opcode == Opcodes.ACONST_NULL insn.previous != null && isSuspendMarker(insn.previous, INLINE_MARKER_FAKE_CONTINUATION) && insn.opcode == Opcodes.ACONST_NULL
internal fun isBeforeFakeContinuationConstructorCallMarker(insn: AbstractInsnNode) =
isSuspendMarker(insn, INLINE_MARKER_BEFORE_FAKE_CONTINUATION_CONSTRUCTOR_CALL)
internal fun isAfterFakeContinuationConstructorCallMarker(insn: AbstractInsnNode) =
isSuspendMarker(insn, INLINE_MARKER_AFTER_FAKE_CONTINUATION_CONSTRUCTOR_CALL)
private fun isSuspendMarker(insn: AbstractInsnNode, id: Int) = private fun isSuspendMarker(insn: AbstractInsnNode, id: Int) =
isInlineMarker(insn, "mark") && insn.previous.intConstant == id isInlineMarker(insn, "mark") && insn.previous.intConstant == id
@@ -201,6 +201,7 @@ public interface Errors {
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(WARNING); DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(WARNING);
DiagnosticFactory1<PsiElement, KtModifierKeywordToken> ILLEGAL_INLINE_PARAMETER_MODIFIER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, KtModifierKeywordToken> ILLEGAL_INLINE_PARAMETER_MODIFIER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<KtParameter> INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED = DiagnosticFactory0.create(ERROR); DiagnosticFactory0<KtParameter> INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtParameter> REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE = DiagnosticFactory0.create(WARNING);
DiagnosticFactory1<KtAnnotationEntry, String> WRONG_ANNOTATION_TARGET = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<KtAnnotationEntry, String> WRONG_ANNOTATION_TARGET = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<KtAnnotationEntry, String, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET = DiagnosticFactory2.create(ERROR); DiagnosticFactory2<KtAnnotationEntry, String, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET = DiagnosticFactory2.create(ERROR);
DiagnosticFactory1<KtAnnotationEntry, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE = DiagnosticFactory1.create(WARNING); DiagnosticFactory1<KtAnnotationEntry, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE = DiagnosticFactory1.create(WARNING);
@@ -122,7 +122,8 @@ public class DefaultErrorMessages {
MAP.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, TO_STRING); MAP.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, TO_STRING);
MAP.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", TO_STRING, TO_STRING); MAP.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", TO_STRING, TO_STRING);
MAP.put(ILLEGAL_INLINE_PARAMETER_MODIFIER, "Modifier ''{0}'' is allowed only for function parameters of an inline function", TO_STRING); MAP.put(ILLEGAL_INLINE_PARAMETER_MODIFIER, "Modifier ''{0}'' is allowed only for function parameters of an inline function", TO_STRING);
MAP.put(INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED, "Inline lambda parameters of suspend function type are not fully supported. Add 'noinline' modifier."); MAP.put(INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED, "Inline lambda parameters of suspend function type are not supported. Add 'noinline' or 'crossinline' modifier.");
MAP.put(REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE, "Redundant suspend modifier of inline lambda parameters of suspend function type.");
MAP.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING); MAP.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING);
MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET, "This annotation is not applicable to target ''{0}'' and use site target ''@{1}''", TO_STRING, TO_STRING); MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET, "This annotation is not applicable to target ''{0}'' and use site target ''@{1}''", TO_STRING, TO_STRING);
MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE, MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE,
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
@@ -239,7 +240,7 @@ internal class InlineChecker(private val descriptor: FunctionDescriptor) : CallC
val containingDeclaration = descriptor.getContainingDeclaration() val containingDeclaration = descriptor.getContainingDeclaration()
val isInvoke = descriptor.getName() == OperatorNameConventions.INVOKE && val isInvoke = descriptor.getName() == OperatorNameConventions.INVOKE &&
containingDeclaration is ClassDescriptor && containingDeclaration is ClassDescriptor &&
containingDeclaration.defaultType.isFunctionType (containingDeclaration.defaultType.isFunctionType || containingDeclaration.defaultType.isSuspendFunctionType)
return isInvoke || InlineUtil.isInline(descriptor) return isInvoke || InlineUtil.isInline(descriptor)
} }
@@ -32,16 +32,22 @@ object InlineParameterChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (declaration is KtFunction) { if (declaration is KtFunction) {
val inline = declaration.hasModifier(KtTokens.INLINE_KEYWORD) val inline = declaration.hasModifier(KtTokens.INLINE_KEYWORD)
val suspend = declaration.hasModifier(KtTokens.SUSPEND_KEYWORD)
for (parameter in declaration.valueParameters) { for (parameter in declaration.valueParameters) {
val parameterDescriptor = context.trace.get(BindingContext.VALUE_PARAMETER, parameter) val parameterDescriptor = context.trace.get(BindingContext.VALUE_PARAMETER, parameter)
if (!inline || (parameterDescriptor != null && !parameterDescriptor.type.isBuiltinFunctionalType)) { if (!inline || (parameterDescriptor != null && !parameterDescriptor.type.isBuiltinFunctionalType)) {
parameter.reportIncorrectInline(KtTokens.NOINLINE_KEYWORD, context.trace) parameter.reportIncorrectInline(KtTokens.NOINLINE_KEYWORD, context.trace)
parameter.reportIncorrectInline(KtTokens.CROSSINLINE_KEYWORD, context.trace) parameter.reportIncorrectInline(KtTokens.CROSSINLINE_KEYWORD, context.trace)
} }
if (inline && !parameter.hasModifier(KtTokens.NOINLINE_KEYWORD) && if (inline && !parameter.hasModifier(KtTokens.NOINLINE_KEYWORD) &&
parameterDescriptor?.type?.isSuspendFunctionType == true) { !parameter.hasModifier(KtTokens.CROSSINLINE_KEYWORD) &&
context.trace.report(Errors.INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED.on(parameter)) parameterDescriptor?.type?.isSuspendFunctionType == true
) {
if (suspend) {
context.trace.report(Errors.REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE.on(parameter))
} else {
context.trace.report(Errors.INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED.on(parameter))
}
} }
} }
} }
@@ -36,7 +36,8 @@ public class InlineUtil {
public static boolean isInlineParameterExceptNullability(@NotNull ParameterDescriptor valueParameterOrReceiver) { public static boolean isInlineParameterExceptNullability(@NotNull ParameterDescriptor valueParameterOrReceiver) {
return !(valueParameterOrReceiver instanceof ValueParameterDescriptor return !(valueParameterOrReceiver instanceof ValueParameterDescriptor
&& ((ValueParameterDescriptor) valueParameterOrReceiver).isNoinline()) && && ((ValueParameterDescriptor) valueParameterOrReceiver).isNoinline()) &&
FunctionTypesKt.isFunctionType(valueParameterOrReceiver.getOriginal().getType()); (FunctionTypesKt.isFunctionType(valueParameterOrReceiver.getOriginal().getType()) ||
FunctionTypesKt.isSuspendFunctionType(valueParameterOrReceiver.getOriginal().getType()));
} }
public static boolean isInlineParameter(@NotNull ParameterDescriptor valueParameterOrReceiver) { public static boolean isInlineParameter(@NotNull ParameterDescriptor valueParameterOrReceiver) {
@@ -55,7 +56,7 @@ public class InlineUtil {
} }
public static boolean isPropertyWithAllAccessorsAreInline(@NotNull DeclarationDescriptor descriptor) { public static boolean isPropertyWithAllAccessorsAreInline(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof PropertyDescriptor)) return false; if (!(descriptor instanceof PropertyDescriptor)) return false;
PropertyGetterDescriptor getter = ((PropertyDescriptor) descriptor).getGetter(); PropertyGetterDescriptor getter = ((PropertyDescriptor) descriptor).getGetter();
if (getter == null || !getter.isInline()) return false; if (getter == null || !getter.isInline()) return false;
@@ -35,7 +35,11 @@ fun builderConsumer(c: suspend () -> Consumer): Consumer {
} }
class Container { class Container {
var y: String = "FAIL 1" var y: String = "FAIL 0"
val consumer0 = crossInlineBuilderConsumer { s ->
y = s
}
val consumer1 = crossInlineBuilderConsumer { s -> val consumer1 = crossInlineBuilderConsumer { s ->
builder { builder {
@@ -108,6 +112,9 @@ class Container {
fun box(): String { fun box(): String {
val c = Container() val c = Container()
c.consumer0.consume("OK")
if (c.y != "OK") return c.y
c.y = "FAIL 1"
c.consumer1.consume("OK") c.consumer1.consume("OK")
if (c.y != "OK") return c.y if (c.y != "OK") return c.y
c.y = "FAIL 2" c.y = "FAIL 2"
@@ -0,0 +1,58 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
suspend inline fun test1(c: suspend () -> Unit) {
c()
}
suspend inline fun test2(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = { c() }
l()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
var res = "FAIL 1"
builder {
val a = 1
test2 {
val b = 2
test1 {
val c = a + b // 3
run {
val a = c + 1 // 4
test1 {
val b = c + c // 6
test2 {
val c = b - a // 2
res = "${calculate()} $a$b$c"
}
}
}
}
}
}
if (res != "OK 462") return res
return "OK"
}
@@ -0,0 +1,38 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
inline suspend fun foo(crossinline a: suspend () -> Unit, crossinline b: suspend () -> Unit) {
var x = "OK"
bar { x; a(); b() }
}
inline suspend fun bar(crossinline l: suspend () -> Unit) {
val c : suspend () -> Unit = { l() }
c()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
fun box(): String {
var y = "fail"
builder {
foo({ y = "O" }) { y += "K" }
}
return y
}
@@ -0,0 +1,100 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
class Controller {
var res = "FAIL 1"
}
val defaultController = Controller()
suspend inline fun test1(controller: Controller = defaultController, crossinline c: suspend Controller.() -> Unit) {
controller.c()
}
suspend inline fun test2(controller: Controller = defaultController, crossinline c: suspend Controller.() -> Unit) {
val l : suspend () -> Unit = {
controller.c()
}
l()
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun test3(controller: Controller = defaultController, crossinline c: suspend Controller.() -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
controller.c()
}
}
sr.run()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
builder {
test1 {
res = calculate()
}
}
if (defaultController.res != "OK") return defaultController.res
defaultController.res = "FAIL 2"
builder {
test2 {
res = calculate()
}
}
if (defaultController.res != "OK") return defaultController.res
defaultController.res = "FAIL 3"
builder {
test3 {
res = calculate()
}
}
if (defaultController.res != "OK") return defaultController.res
val controller = Controller()
controller.res = "FAIL 4"
builder {
test1(controller) {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder {
test2(controller) {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder {
test3(controller) {
res = calculate()
}
}
return controller.res
}
@@ -0,0 +1,52 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
class Controller {
var res = "FAIL 1"
}
val defaultController = Controller()
suspend inline fun test(controller: Controller = defaultController, c: suspend Controller.() -> Unit) {
controller.c()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
builder {
test {
res = calculate()
}
}
if (defaultController.res != "OK") return defaultController.res
val controller = Controller()
controller.res = "FAIL 2"
builder {
test(controller) {
res = calculate()
}
}
return controller.res
}
@@ -0,0 +1,101 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Are suspend calls possible inside lambda matching to the parameter
inline fun test1(crossinline runner: suspend () -> Unit) {
val l : suspend () -> Unit = { runner() }
builder { l() }
}
interface SuspendRunnable {
suspend fun run()
}
inline fun test2(crossinline c: suspend () -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
builder { sr.run() }
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
suspend fun calculate() = "OK"
fun box(): String {
var res = "FAIL 1"
test1 {
res = calculate()
}
if (res != "OK") return res
res = "FAIL 2"
test1 {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 3"
test2 {
res = calculate()
}
if (res != "OK") return res
res = "FAIL 4"
test2 {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
test1 {
test2 {
test1 {
test2 {
test1 {
test2 {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,128 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Start coroutine call is possible
// Are suspend calls possible inside lambda matching to the parameter
inline fun test1(noinline c: suspend () -> Unit) {
val l : suspend () -> Unit = { c() }
builder { l() }
}
val EmptyContinuation = object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
inline fun test2(noinline c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
interface SuspendRunnable {
suspend fun run()
}
inline fun test3(noinline c: suspend () -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
builder { sr.run() }
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
// FILE: box.kt
suspend fun calculate() = "OK"
fun box(): String {
var res = "FAIL 1"
test1 {
res = calculate()
}
if (res != "OK") return res
res = "FAIL 2"
test2 {
res = "OK"
}
if (res != "OK") return res
res = "FAIL 3"
test3 {
res = "OK"
}
if (res != "OK") return res
res = "FAIL 4"
test1 {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
test2 {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
test3 {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 7"
test1 {
test2 {
test3 {
test1 {
test2 {
test3 {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,111 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun test1(c: () -> Unit) {
c()
}
suspend inline fun test2(c: suspend () -> Unit) {
c()
}
suspend inline fun test3(crossinline c: suspend() -> Unit) {
c()
}
suspend inline fun test4(crossinline c: suspend() -> Unit) {
val l : suspend () -> Unit = { c() }
l()
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun test5(crossinline c: suspend() -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
import kotlin.coroutines.experimental.jvm.internal.*
object EmptyContinuation: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
var continuationChanged = true
var savedContinuation: Continuation<Unit>? = null
suspend inline fun saveContinuation() = suspendCoroutineUninterceptedOrReturn<Unit> { c ->
savedContinuation = c
Unit
}
suspend inline fun checkContinuation(continuation: Continuation<Unit>) = suspendCoroutineUninterceptedOrReturn<Unit> { c ->
continuationChanged = (continuation !== c)
Unit
}
fun box() : String {
builder {
saveContinuation()
test1 {
checkContinuation(savedContinuation!!)
}
}
if (continuationChanged) return "FAIL 1"
continuationChanged = true
builder {
saveContinuation()
test2 {
checkContinuation(savedContinuation!!)
}
}
if (continuationChanged) return "FAIL 2"
continuationChanged = true
builder {
saveContinuation()
test3 {
checkContinuation(savedContinuation!!)
}
}
if (continuationChanged) return "FAIL 3"
continuationChanged = false
builder {
saveContinuation()
test4 {
checkContinuation(savedContinuation!!)
}
}
if (!continuationChanged) return "FAIL 4"
continuationChanged = false
builder {
saveContinuation()
test5 {
checkContinuation(savedContinuation!!)
}
}
if (!continuationChanged) return "FAIL 5"
return "OK"
}
@@ -0,0 +1,109 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
suspend inline fun test1(crossinline c: () -> Unit) {
c()
}
suspend inline fun test2(crossinline c: () -> Unit) {
val l = { c() }
l()
}
suspend inline fun test3(crossinline c: () -> Unit) {
val r = object: Runnable {
override fun run() {
c()
}
}
r.run()
}
inline fun transform(crossinline c: suspend () -> Unit) {
builder { c() }
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun box() : String {
var res = "FAIL 1"
builder {
test1 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test2 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 3"
builder {
test3 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 4"
builder {
test1 {
transform {
test1 {
res = "OK"
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
builder {
test2 {
transform {
test2 {
res = "OK"
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
builder {
test3 {
transform {
test3 {
res = "OK"
}
}
}
}
return res
}
@@ -0,0 +1,134 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test1(crossinline c: suspend () -> Unit) {
c()
}
suspend inline fun test2(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = { c() }
l()
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun test3(crossinline c: suspend () -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
var res = "FAIL 1"
builder {
test1 {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test2 {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 3"
builder {
test3 {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 4"
builder {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
builder {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
builder {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 7"
builder {
test1 {
test2 {
test3 {
test1 {
test2 {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,109 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
suspend inline fun test1(noinline c: () -> Unit) {
c()
}
suspend inline fun test2(noinline c: () -> Unit) {
val l = { c() }
l()
}
suspend inline fun test3(noinline c: () -> Unit) {
val r = object: Runnable {
override fun run() {
c()
}
}
r.run()
}
inline fun transform(crossinline c: suspend () -> Unit) {
builder { c() }
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun box() : String {
var res = "FAIL 1"
builder {
test1 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test2 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 3"
builder {
test3 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 4"
builder {
test1 {
transform {
test1 {
res = "OK"
}
}
}
}
if (res != "OK") return res
res = "FAIL 5"
builder {
test2 {
transform {
test2 {
res = "OK"
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
builder {
test3 {
transform {
test3 {
res = "OK"
}
}
}
}
return res
}
@@ -0,0 +1,163 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Are suspend calls possible inside lambda matching to the parameter
// Start coroutine call is possible
// Block is allowed to be called directly inside inline function
suspend inline fun test1(noinline c: suspend () -> Unit) {
val l : suspend () -> Unit = { c() }
builder { l() }
}
object EmptyContinuation: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
suspend inline fun test2(noinline c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
suspend inline fun test3(noinline c: suspend () -> Unit) {
c()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun test4(noinline c: suspend () -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
suspend fun calculate() = "OK"
fun box(): String {
var res = "FAIL 1"
builder {
test1 {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test2 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 3"
builder {
test3 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 4"
builder {
test4 {
res = "OK"
}
}
if (res != "OK") return res
res = "FAIL 5"
builder {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 6"
builder {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 7"
builder {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 8"
builder {
test4 {
test4 {
test4 {
test4 {
test4 {
res = calculate()
}
}
}
}
}
}
if (res != "OK") return res
res = "FAIL 9"
builder {
test1 {
test2 {
test3 {
test4 {
test1 {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,56 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test(c: () -> Unit) {
c()
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
inline fun transform(crossinline c: suspend () -> Unit) {
builder { c() }
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
suspend fun calculate() = "OK"
fun box() : String {
var res = "FAIL 1"
builder {
test {
res = calculate()
}
}
if (res != "OK") return res
builder {
test {
transform {
test {
res = calculate()
}
}
}
}
return res
}
@@ -0,0 +1,57 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test(c: suspend () -> Unit) {
c()
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
var res = "FAIL 1"
builder {
test {
res = calculate()
}
}
if (res != "OK") return res
res = "FAIL 2"
builder {
test {
test {
test {
test {
test {
res = calculate()
}
}
}
}
}
}
return res
}
@@ -0,0 +1,123 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
object Result {
var a: String = ""
var b: Int = 0
}
suspend inline fun inlineMe(c: suspend () -> Unit) {
var a = ""
var b = 0
val r = object: Runnable {
override fun run() {
b++
a += "a"
}
}
r.run()
c()
r.run()
Result.a = a
Result.b = b
}
suspend inline fun noinlineMe(noinline c: suspend () -> Unit) {
var a = ""
var b = 0
val r = object: Runnable {
override fun run() {
b += 2
a += "b"
}
}
r.run()
c()
r.run()
Result.a += a
Result.b += b
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
var a = ""
var b = 0
val r = object: Runnable {
override fun run() {
b += 3
a += "c"
}
}
r.run()
c()
r.run()
Result.a += a
Result.b += b
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun dummy() {
val local0 = 0
val local1 = 0
val local2 = 0
val local3 = 0
val local4 = 0
val local5 = 0
val local6 = 0
val local7 = 0
val local8 = 0
val local9 = 0
val local10 = 0
val local11 = 0
val local12 = 0
val local13 = 0
val local14 = 0
val local15 = 0
val local16 = 0
val local17 = 0
val local18 = 0
val local19 = 0
val local20 = 0
val local21 = 0
val local22 = 0
}
suspend fun inlineSite() {
inlineMe {
dummy()
dummy()
}
if (Result.a != "aa" || Result.b != 2) throw RuntimeException("FAIL 1")
noinlineMe {
dummy()
dummy()
}
if (Result.a != "aabb" || Result.b != 6) throw RuntimeException("FAIL 2")
crossinlineMe {
dummy()
dummy()
}
if (Result.a != "aabbcc" || Result.b != 12) throw RuntimeException("FAIL 3")
}
fun box(): String {
builder {
inlineSite()
}
return "OK"
}
@@ -0,0 +1,84 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun inlineMe(c: suspend () -> Unit) {
c()
c()
c()
c()
c()
}
suspend inline fun noinlineMe(noinline c: suspend () -> Unit) {
c()
c()
c()
c()
c()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
c()
c()
c()
c()
c()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
var j = 0;
var k = 0;
suspend fun calculateI() {
i++
}
suspend fun calculateJ() {
j++
}
suspend fun calculateK() {
k++
}
suspend fun inlineSite() {
inlineMe {
calculateI()
calculateI()
}
noinlineMe {
calculateJ()
calculateJ()
}
crossinlineMe {
calculateK()
calculateK()
}
}
fun box(): String {
builder {
inlineSite()
}
if (i != 10) return "FAIL I"
if (j != 10) return "FAIL J"
if (k != 10) return "FAIL K"
return "OK"
}
@@ -0,0 +1,105 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Are suspend calls possible inside lambda matching to the parameter
interface SuspendRunnable {
suspend fun run()
}
class Controller {
var res = "FAIL 1"
inline fun test1(crossinline runner: suspend Controller.() -> Unit) {
val l : suspend Controller.() -> Unit = { runner() }
builder(this) { l() }
}
inline fun test2(crossinline c: suspend Controller.() -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
builder(this) { sr.run() }
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
suspend fun calculate() = "OK"
fun box(): String {
val controller = Controller()
controller.test1 {
res = calculate()
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
controller.test1 {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
controller.test2 {
res = calculate()
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
controller.test2 {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
controller.test1 {
test2 {
test1 {
test2 {
test1 {
test2 {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,132 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Start coroutine call is possible
// Are suspend calls possible inside lambda matching to the parameter
interface SuspendRunnable {
suspend fun run()
}
val EmptyContinuation = object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
class Controller {
var res = "FAIL 1"
inline fun test1(noinline c: suspend Controller.() -> Unit) {
val l : suspend Controller.() -> Unit = { c() }
builder(this) { l() }
}
inline fun test2(noinline c: suspend Controller.() -> Unit) {
c.startCoroutine(this, EmptyContinuation)
}
inline fun test3(noinline c: suspend Controller.() -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
builder(this) { sr.run() }
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, EmptyContinuation)
}
// FILE: box.kt
suspend fun calculate() = "OK"
fun box(): String {
val controller = Controller()
controller.test1 {
res = calculate()
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
controller.test2 {
res = "OK"
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
controller.test3 {
res = "OK"
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
controller.test1 {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
controller.test2 {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
controller.test3 {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 7"
controller.test1 {
test2 {
test3 {
test1 {
test2 {
test3 {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,113 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
class Controller {
var res = "FAIL 1"
suspend inline fun test1(crossinline c: Controller.() -> Unit) {
c()
}
suspend inline fun test2(crossinline c: Controller.() -> Unit) {
val l = { c() }
l()
}
suspend inline fun test3(crossinline c: Controller.() -> Unit) {
val r = object: Runnable {
override fun run() {
c()
}
}
r.run()
}
inline fun transform(crossinline c: suspend Controller.() -> Unit) {
builder(this) { c() }
}
}
fun builder(controller : Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun box() : String {
val controller = Controller()
builder(controller) {
test1 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test2 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
builder(controller) {
test3 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
builder(controller) {
test1 {
transform {
test1 {
res = "OK"
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder(controller) {
test2 {
transform {
test2 {
res = "OK"
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder(controller) {
test3 {
transform {
test3 {
res = "OK"
}
}
}
}
return controller.res
}
@@ -0,0 +1,138 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// suspend calls possible inside lambda matching to the parameter
interface SuspendRunnable {
suspend fun run()
}
class Controller {
var res = "FAIL 1"
suspend inline fun test1(crossinline c: suspend Controller.() -> Unit) {
c()
}
suspend inline fun test2(crossinline c: suspend Controller.() -> Unit) {
val l: suspend Controller.() -> Unit = { c() }
l()
}
suspend inline fun test3(crossinline c: suspend Controller.() -> Unit) {
val sr = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
val controller = Controller()
builder(controller) {
test1 {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test2 {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
builder(controller) {
test3 {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
builder(controller) {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder(controller) {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder(controller) {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 7"
builder(controller) {
test1 {
test2 {
test3 {
test1 {
test2 {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,113 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
class Controller {
var res = "FAIL 1"
suspend inline fun test1(noinline c: Controller.() -> Unit) {
c()
}
suspend inline fun test2(noinline c: Controller.() -> Unit) {
val l = { c() }
l()
}
suspend inline fun test3(noinline c: Controller.() -> Unit) {
val r = object: Runnable {
override fun run() {
c()
}
}
r.run()
}
inline fun transform(crossinline c: suspend Controller.() -> Unit) {
builder(this) { c() }
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun box() : String {
val controller = Controller()
builder(controller) {
test1 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test2 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
builder(controller) {
test3 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
builder(controller) {
test1 {
transform {
test1 {
res = "OK"
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder(controller) {
test2 {
transform {
test2 {
res = "OK"
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder(controller) {
test3 {
transform {
test3 {
res = "OK"
}
}
}
}
return controller.res
}
@@ -0,0 +1,167 @@
// FILE: test.kt
// WITH_RUNTIME
import kotlin.coroutines.experimental.*
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// Are suspend calls possible inside lambda matching to the parameter
// Start coroutine call is possible
// Block is allowed to be called directly inside inline function
interface SuspendRunnable {
suspend fun run()
}
object EmptyContinuation: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
}
class Controller {
var res = "FAIL 1"
suspend inline fun test1(noinline c: suspend Controller.() -> Unit) {
val l : suspend Controller.() -> Unit = { c() }
l()
}
suspend inline fun test2(noinline c: suspend Controller.() -> Unit) {
c.startCoroutine(this, EmptyContinuation)
}
suspend inline fun test3(noinline c: suspend Controller.() -> Unit) {
c()
}
suspend inline fun test4(noinline c: suspend Controller.() -> Unit) {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, EmptyContinuation)
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
suspend fun calculate() = "OK"
fun box(): String {
val controller = Controller()
builder(controller) {
test1 {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test2 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 3"
builder(controller) {
test3 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 4"
builder(controller) {
test4 {
res = "OK"
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 5"
builder(controller) {
test1 {
test1 {
test1 {
test1 {
test1 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 6"
builder(controller) {
test2 {
test2 {
test2 {
test2 {
test2 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 7"
builder(controller) {
test3 {
test3 {
test3 {
test3 {
test3 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 8"
builder(controller) {
test4 {
test4 {
test4 {
test4 {
test4 {
res = calculate()
}
}
}
}
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 9"
builder(controller) {
test1 {
test2 {
test3 {
test4 {
test1 {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,60 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// suspend calls possible inside lambda matching to the parameter
class Controller {
var res = "FAIL 1"
suspend inline fun test(c: Controller.() -> Unit) {
c()
}
inline fun transform(crossinline c: suspend Controller.() -> Unit) {
builder(this) { c() }
}
}
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
suspend fun calculate() = "OK"
fun box() : String {
val controller = Controller()
builder(controller) {
test {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
builder(controller) {
test {
transform {
test {
res = calculate()
}
}
}
}
return controller.res
}
@@ -0,0 +1,61 @@
// FILE: test.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.*
// Block is allowed to be called inside the body of owner inline function
// suspend calls possible inside lambda matching to the parameter
class Controller {
var res = "FAIL 1"
suspend inline fun test(c: suspend Controller.() -> Unit) {
c()
}
}
// FILE: box.kt
import kotlin.coroutines.experimental.*
fun builder(controller: Controller, c: suspend Controller.() -> Unit) {
c.startCoroutine(controller, object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun calculate() = "OK"
fun box() : String {
val controller = Controller()
builder(controller) {
test {
res = calculate()
}
}
if (controller.res != "OK") return controller.res
controller.res = "FAIL 2"
builder(controller) {
test {
test {
test {
test {
test {
res = calculate()
}
}
}
}
}
}
return controller.res
}
@@ -0,0 +1,48 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = { c() }
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL"
return "OK"
}
@@ -0,0 +1,53 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = {
val l1 : suspend () -> Unit = {
c()
}
l1()
}
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,52 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.intrinsics.*
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
fun box(): String {
var res = "OK"
builder {
crossinlineMe {
res = "FAIL 1"
}
}
if (i != 1) return "FAIL 2"
return res
}
@@ -0,0 +1,75 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
val l : suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
val l : suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
sr.run()
}
l()
}
}
sr.run()
}
l()
}
}
sr.run()
}
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,75 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = {
c()
}
l()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
val sr = object: SuspendRunnable {
override suspend fun run() {
val l : suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
val l : suspend () -> Unit = {
val sr = object: SuspendRunnable {
override suspend fun run() {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
sr.run()
}
l()
}
}
sr.run()
}
l()
}
}
sr.run()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,56 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val o = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
o.run()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,61 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val o = object : SuspendRunnable {
override suspend fun run() {
val o1 = object: SuspendRunnable {
override suspend fun run() {
c()
}
}
o1.run()
}
}
o.run()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL $i"
return "OK"
}
@@ -0,0 +1,60 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
interface SuspendRunnable {
suspend fun run1()
suspend fun run2()
}
suspend inline fun crossinlineMe(crossinline c1: suspend () -> Unit, crossinline c2: suspend () -> Unit) {
val o = object : SuspendRunnable {
override suspend fun run1() {
c1()
}
override suspend fun run2() {
c2()
}
}
o.run1()
o.run2()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
var j = 0;
suspend fun incrementI() {
i++
}
suspend fun incrementJ() {
j++
}
fun box(): String {
builder {
crossinlineMe({ incrementI() }) { incrementJ() }
}
if (i != 1) return "FAIL i $i"
if (j != 1) return "FAIL i $i"
return "OK"
}
@@ -0,0 +1,58 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
import kotlin.coroutines.experimental.intrinsics.*
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
interface SuspendRunnable {
suspend fun run()
}
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val o = object : SuspendRunnable {
override suspend fun run() {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
o.run()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
fun box(): String {
var res = "OK"
builder {
crossinlineMe {
res = "FAIL 1"
}
}
if (i != 1) return "FAIL 2"
return res
}
@@ -0,0 +1,48 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
c()
c()
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
var i = 0;
suspend fun suspendHere() = suspendCoroutineOrReturn<Unit> {
i++
COROUTINE_SUSPENDED
}
fun box(): String {
builder {
crossinlineMe {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
if (i != 1) return "FAIL"
return "OK"
}
@@ -0,0 +1,68 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun crossinlineMe(crossinline c: suspend () -> Unit) {
val l: suspend () -> Unit = { c() }
l()
}
suspend inline fun crossinlineMe2(crossinline c: suspend () -> Unit) {
crossinlineMe { c(); c() }
}
// FILE: inlineSite.kt
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<Unit> { c ->
i++
proceed = { c.resume(Unit) }
}
fun builder(c: suspend () -> Unit) {
val continuation = object: Continuation<Unit> {
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)
}
fun box(): String {
builder {
crossinlineMe2 {
suspendHere()
suspendHere()
suspendHere()
suspendHere()
suspendHere()
}
}
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
}
@@ -0,0 +1,84 @@
// FILE: inlined.kt
// WITH_RUNTIME
// NO_CHECK_LAMBDA_INLINING
suspend inline fun inlineMe(c: suspend (String) -> String, d: suspend () -> String): String {
return c(try { d() } catch (e: Exception) { "Exception 1 ${e.message}" })
}
suspend inline fun noinlineMe(noinline c: suspend (String) -> String, noinline d: suspend () -> String): String {
return c(try { d() } catch (e: Exception) { "Exception 1 ${e.message}" })
}
suspend inline fun crossinlineMe(crossinline c: suspend (String) -> String, crossinline d: suspend () -> String): String {
return c(try { d() } catch (e: Exception) { "Exception 1 ${e.message}" })
}
// FILE: inlineSite.kt
import kotlin.coroutines.experimental.*
fun builder(c: suspend () -> Unit) {
c.startCoroutine(object: Continuation<Unit> {
override val context: CoroutineContext
get() = EmptyCoroutineContext
override fun resume(value: Unit) {
}
override fun resumeWithException(exception: Throwable) {
throw exception
}
})
}
suspend fun yieldString(s: String) = s
suspend fun throwException(s: String): String {
throw RuntimeException(s)
}
suspend fun inlineSite() {
var res = inlineMe({ it }) { yieldString("OK") }
if (res != "OK") throw RuntimeException("FAIL 1: $res")
res = inlineMe({ it }) { throwException("OK") }
if (res != "Exception 1 OK") throw RuntimeException("FAIL 2: $res")
res = noinlineMe({ it }) { yieldString("OK") }
if (res != "OK") throw RuntimeException("FAIL 3: $res")
res = noinlineMe({ it }) { throwException("OK") }
if (res != "Exception 1 OK") throw RuntimeException("FAIL 4: $res")
res = crossinlineMe({ it }) { yieldString("OK") }
if (res != "OK") throw RuntimeException("FAIL 5: $res")
res = crossinlineMe({ it }) { throwException("OK") }
if (res != "Exception 1 OK") throw RuntimeException("FAIL 6: $res")
res = inlineMe({ try {yieldString(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
if (res != "OK") throw RuntimeException("FAIL 7: $res")
res = inlineMe({ try {throwException(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
if (res != "Exception 2 OK") throw RuntimeException("FAIL 8: $res")
res = noinlineMe({ try {yieldString(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
if (res != "OK") throw RuntimeException("FAIL 9: $res")
res = noinlineMe({ try {throwException(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
if (res != "Exception 2 OK") throw RuntimeException("FAIL 10: $res")
res = crossinlineMe({ try {yieldString(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
if (res != "OK") throw RuntimeException("FAIL 11: $res")
res = crossinlineMe({ try {throwException(it) } catch (e: Exception) { yieldString("Exception 2 $it") } }) { yieldString("OK") }
if (res != "Exception 2 OK") throw RuntimeException("FAIL 12: $res")
}
fun box(): String {
builder {
inlineSite()
}
return "OK"
}
@@ -0,0 +1,2 @@
// SKIP_TXT
inline fun foo(crossinline <!WRONG_MODIFIER_TARGET!>suspend<!> <!UNUSED_PARAMETER!>c<!>: () -> Unit) {}
@@ -0,0 +1,37 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
// Function is NOT suspend
// parameter is crossinline
// parameter is NOT suspend
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls NOT possible inside lambda matching to the parameter
inline fun test(crossinline c: () -> Unit) {
c()
val o = object: Runnable {
override fun run() {
c()
}
}
val l = { c() }
c.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>startCoroutine<!>(EmptyContinuation)
}
suspend fun calculate() = "OK"
fun box() {
test {
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>calculate<!>()
}
}
@@ -0,0 +1,41 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -NOTHING_TO_INLINE
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
interface SuspendRunnable {
suspend fun run()
}
// Function is NOT suspend
// parameter is crossinline
// parameter is suspend
// Block is NOT allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls possible inside lambda matching to the parameter
inline fun test(crossinline c: suspend () -> Unit) {
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>c<!>()
val o = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
val l: suspend () -> Unit = { c() }
<!USAGE_IS_NOT_INLINABLE!>c<!>.startCoroutine(EmptyContinuation)
}
suspend fun calculate() = "OK"
fun box() {
test {
calculate()
}
}
@@ -0,0 +1,36 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
// Function is NOT suspend
// parameter is noinline
// parameter is NOT suspend
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls NOT possible inside lambda matching to the parameter
inline fun test(noinline c: () -> Unit) {
c()
val o = object: Runnable {
override fun run() {
c()
}
}
val l = { c() }
c.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>startCoroutine<!>(EmptyContinuation)
}
suspend fun calculate() = "OK"
fun box() {
test {
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>calculate<!>()
}
}
@@ -0,0 +1,41 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -NOTHING_TO_INLINE
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
interface SuspendRunnable {
suspend fun run()
}
// Function is NOT suspend
// parameter is noinline
// parameter is suspend
// Block is NOT allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// It is possible to call startCoroutine on the parameter
// suspend calls possible inside lambda matching to the parameter
inline fun test(noinline c: suspend () -> Unit) {
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>c<!>()
val o = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
val l: suspend () -> Unit = { c() }
c.startCoroutine(EmptyContinuation)
}
suspend fun calculate() = "OK"
fun box() {
test {
calculate()
}
}
@@ -0,0 +1,43 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
// Function is NOT suspend
// parameter is inline
// parameter is NOT suspend
// Block is allowed to be called inside the body of owner inline function
// Block is NOT allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls possible inside lambda matching to the parameter
inline fun test(c: () -> Unit) {
c()
val o = object : Runnable {
override fun run() {
<!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>()
}
}
val l = { <!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>() }
c.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>startCoroutine<!>(EmptyContinuation)
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
suspend fun calculate() = "OK"
fun box() {
builder {
test {
calculate()
}
}
}
@@ -0,0 +1,43 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE -UNUSED_PARAMETER
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
interface SuspendRunnable {
suspend fun run()
}
// Function is NOT suspend
// parameter is inline
// parameter is suspend
// Block is NOT allowed to be called inside the body of owner inline function
// Block is NOT allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls possible inside lambda matching to the parameter
inline fun test(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>c: suspend () -> Unit<!>) {
<!ILLEGAL_SUSPEND_FUNCTION_CALL!>c<!>()
val o = object: SuspendRunnable {
override suspend fun run() {
<!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>()
}
}
val l: suspend () -> Unit = { <!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>() }
<!USAGE_IS_NOT_INLINABLE!>c<!>.startCoroutine(EmptyContinuation)
}
fun builder(c: suspend () -> Unit) {}
suspend fun calculate() = "OK"
fun box() {
test {
calculate()
}
}
@@ -0,0 +1,42 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
// Function is suspend
// parameter is crossinline
// parameter is NOT suspend
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls NOT possible inside lambda matching to the parameter
suspend inline fun test(crossinline c: () -> Unit) {
c()
val o = object : Runnable {
override fun run() {
c()
}
}
val l = { c() }
c.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>startCoroutine<!>(EmptyContinuation)
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
suspend fun calculate() = "OK"
fun box() {
builder {
test {
<!NON_LOCAL_SUSPENSION_POINT!>calculate<!>()
}
}
}
@@ -0,0 +1,44 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -NOTHING_TO_INLINE
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
interface SuspendRunnable {
suspend fun run()
}
// Function is suspend
// parameter is crossinline
// parameter is suspend
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test(crossinline c: suspend () -> Unit) {
c()
val o = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
val l: suspend () -> Unit = { c() }
<!USAGE_IS_NOT_INLINABLE!>c<!>.startCoroutine(EmptyContinuation)
}
fun builder(c: suspend () -> Unit) {}
suspend fun calculate() = "OK"
fun box() {
builder {
test {
calculate()
}
}
}
@@ -0,0 +1,42 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
// Function is suspend
// parameter is noinline
// parameter is NOT suspend
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls NOT possible inside lambda matching to the parameter
suspend inline fun test(noinline c: () -> Unit) {
c()
val o = object : Runnable {
override fun run() {
c()
}
}
val l = { c() }
c.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>startCoroutine<!>(EmptyContinuation)
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(EmptyContinuation)
}
suspend fun calculate() = "OK"
fun box() {
builder {
test {
<!NON_LOCAL_SUSPENSION_POINT!>calculate<!>()
}
}
}
@@ -0,0 +1,44 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE -UNUSED_PARAMETER
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
interface SuspendRunnable {
suspend fun run()
}
// Function is suspend
// parameter is noinline
// parameter is suspend
// Block is allowed to be called inside the body of owner inline function
// Block is allowed to be called from nested classes/lambdas (as common crossinlines)
// It is possible to call startCoroutine on the parameter
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test(noinline c: suspend () -> Unit) {
c()
val o = object : SuspendRunnable {
override suspend fun run() {
c()
}
}
val l: suspend () -> Unit = { c() }
c.startCoroutine(EmptyContinuation)
}
fun builder(c: suspend () -> Unit) {}
suspend fun calculate() = "OK"
fun box() {
builder {
test {
calculate()
}
}
}
@@ -0,0 +1,40 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
// Function is suspend
// parameter is inline
// parameter is NOT suspend
// Block is allowed to be called inside the body of owner inline function
// Block is NOT allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test(c: () -> Unit) {
c()
val o = object: Runnable {
override fun run() {
<!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>()
}
}
val l = { <!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>() }
c.<!UNRESOLVED_REFERENCE_WRONG_RECEIVER!>startCoroutine<!>(EmptyContinuation)
}
suspend fun calculate() = "OK"
fun builder(c: suspend () -> Unit) {}
fun box() {
builder {
test {
calculate()
}
}
}
@@ -0,0 +1,45 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -NOTHING_TO_INLINE
// SKIP_TXT
import kotlin.coroutines.experimental.*
import kotlin.coroutines.experimental.intrinsics.*
open class EmptyContinuation(override val context: CoroutineContext = EmptyCoroutineContext) : Continuation<Any?> {
companion object : EmptyContinuation()
override fun resume(<!PARAMETER_NAME_CHANGED_ON_OVERRIDE!>data<!>: Any?) {}
override fun resumeWithException(exception: Throwable) { throw exception }
}
interface SuspendRunnable {
suspend fun run()
}
// Function is suspend
// parameter is inline
// parameter is suspend
// Block is allowed to be called inside the body of owner inline function
// Block is NOT allowed to be called from nested classes/lambdas (as common crossinlines)
// It is NOT possible to call startCoroutine on the parameter
// suspend calls possible inside lambda matching to the parameter
suspend inline fun test(<!REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE!>c: suspend () -> Unit<!>) {
c()
val o = object: SuspendRunnable {
override suspend fun run() {
<!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>()
}
}
val l: suspend () -> Unit = { <!NON_LOCAL_RETURN_NOT_ALLOWED!>c<!>() }
<!USAGE_IS_NOT_INLINABLE!>c<!>.startCoroutine(EmptyContinuation)
}
fun builder(c: suspend () -> Unit) {
}
suspend fun calculate() = "OK"
fun box() {
builder {
test {
calculate()
}
}
}
@@ -1,18 +1,18 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER // !DIAGNOSTICS: -UNUSED_PARAMETER
// SKIP_TXT // SKIP_TXT
<!NOTHING_TO_INLINE!>inline<!> fun foo1(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>x: suspend () -> Unit<!>) {} inline fun foo1(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>x: suspend () -> Unit<!>) {}
<!NOTHING_TO_INLINE!>inline<!> fun foo2(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>crossinline x: suspend () -> Unit<!>) {} inline fun foo2(crossinline x: suspend () -> Unit) {}
<!NOTHING_TO_INLINE!>inline<!> fun foo3(noinline x: suspend () -> Unit) {} <!NOTHING_TO_INLINE!>inline<!> fun foo3(noinline x: suspend () -> Unit) {}
<!NOTHING_TO_INLINE!>inline<!> fun foo4(<!INCOMPATIBLE_MODIFIERS!>noinline<!> <!INCOMPATIBLE_MODIFIERS!>crossinline<!> x: suspend () -> Unit) {} <!NOTHING_TO_INLINE!>inline<!> fun foo4(<!INCOMPATIBLE_MODIFIERS!>noinline<!> <!INCOMPATIBLE_MODIFIERS!>crossinline<!> x: suspend () -> Unit) {}
suspend inline fun bar1(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>x: suspend () -> Unit<!>) {} suspend inline fun bar1(<!REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE!>x: suspend () -> Unit<!>) {}
suspend inline fun bar2(<!INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED!>crossinline x: suspend () -> Unit<!>) {} suspend inline fun bar2(crossinline x: suspend () -> Unit) {}
suspend inline fun bar3(noinline x: suspend () -> Unit) {} suspend inline fun bar3(noinline x: suspend () -> Unit) {}
suspend inline fun bar4(<!INCOMPATIBLE_MODIFIERS!>noinline<!> <!INCOMPATIBLE_MODIFIERS!>crossinline<!> x: suspend () -> Unit) {} suspend inline fun bar4(<!INCOMPATIBLE_MODIFIERS!>noinline<!> <!INCOMPATIBLE_MODIFIERS!>crossinline<!> x: suspend () -> Unit) {}
suspend fun baz() { suspend fun baz() {
foo1 { foo1 {
<!RETURN_NOT_ALLOWED!>return@baz<!> return@baz
} }
foo2 { foo2 {
@@ -28,7 +28,7 @@ suspend fun baz() {
} }
bar1 { bar1 {
<!RETURN_NOT_ALLOWED!>return@baz<!> return@baz
} }
bar2 { bar2 {
@@ -3391,6 +3391,252 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
} }
} }
@TestMetadata("compiler/testData/codegen/boxInline/suspend")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Suspend extends AbstractIrBlackBoxInlineCodegenTest {
public void testAllFilesPresentInSuspend() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("capturedVariables.kt")
public void testCapturedVariables() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/capturedVariables.kt");
doTest(fileName);
}
@TestMetadata("crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt")
public void testCrossinlineSuspendLambdaInsideCrossinlineSuspendLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendContinuation.kt")
public void testInlineSuspendContinuation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendContinuation.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
@TestMetadata("multipleLocals.kt")
public void testMultipleLocals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/multipleLocals.kt");
doTest(fileName);
}
@TestMetadata("multipleSuspensionPoints.kt")
public void testMultipleSuspensionPoints() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/multipleSuspensionPoints.kt");
doTest(fileName);
}
@TestMetadata("tryCatchStackTransform.kt")
public void testTryCatchStackTransform() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/tryCatchStackTransform.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultParameter extends AbstractIrBlackBoxInlineCodegenTest {
public void testAllFilesPresentInDefaultParameter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/defaultParameter"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("defaultValueCrossinline.kt")
public void testDefaultValueCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter/defaultValueCrossinline.kt");
doTest(fileName);
}
@TestMetadata("defaultValueInline.kt")
public void testDefaultValueInline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter/defaultValueInline.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Receiver extends AbstractIrBlackBoxInlineCodegenTest {
public void testAllFilesPresentInReceiver() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/receiver"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class StateMachine extends AbstractIrBlackBoxInlineCodegenTest {
public void testAllFilesPresentInStateMachine() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/stateMachine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("innerLambda.kt")
public void testInnerLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambda.kt");
doTest(fileName);
}
@TestMetadata("innerLambdaInsideLambda.kt")
public void testInnerLambdaInsideLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaInsideLambda.kt");
doTest(fileName);
}
@TestMetadata("innerLambdaWithoutCrossinline.kt")
public void testInnerLambdaWithoutCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaWithoutCrossinline.kt");
doTest(fileName);
}
@TestMetadata("innerMadness.kt")
public void testInnerMadness() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerMadness.kt");
doTest(fileName);
}
@TestMetadata("innerMadnessCallSite.kt")
public void testInnerMadnessCallSite() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerMadnessCallSite.kt");
doTest(fileName);
}
@TestMetadata("innerObject.kt")
public void testInnerObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObject.kt");
doTest(fileName);
}
@TestMetadata("innerObjectInsideInnerObject.kt")
public void testInnerObjectInsideInnerObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectInsideInnerObject.kt");
doTest(fileName);
}
@TestMetadata("innerObjectSeveralFunctions.kt")
public void testInnerObjectSeveralFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectSeveralFunctions.kt");
doTest(fileName);
}
@TestMetadata("innerObjectWithoutCapturingCrossinline.kt")
public void testInnerObjectWithoutCapturingCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectWithoutCapturingCrossinline.kt");
doTest(fileName);
}
@TestMetadata("normalInline.kt")
public void testNormalInline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/normalInline.kt");
doTest(fileName);
}
@TestMetadata("numberOfSuspentions.kt")
public void testNumberOfSuspentions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/numberOfSuspentions.kt");
doTest(fileName);
}
}
}
@TestMetadata("compiler/testData/codegen/boxInline/syntheticAccessors") @TestMetadata("compiler/testData/codegen/boxInline/syntheticAccessors")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -3391,6 +3391,252 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
} }
} }
@TestMetadata("compiler/testData/codegen/boxInline/suspend")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Suspend extends AbstractIrCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInSuspend() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("capturedVariables.kt")
public void testCapturedVariables() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/capturedVariables.kt");
doTest(fileName);
}
@TestMetadata("crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt")
public void testCrossinlineSuspendLambdaInsideCrossinlineSuspendLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendContinuation.kt")
public void testInlineSuspendContinuation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendContinuation.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
@TestMetadata("multipleLocals.kt")
public void testMultipleLocals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/multipleLocals.kt");
doTest(fileName);
}
@TestMetadata("multipleSuspensionPoints.kt")
public void testMultipleSuspensionPoints() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/multipleSuspensionPoints.kt");
doTest(fileName);
}
@TestMetadata("tryCatchStackTransform.kt")
public void testTryCatchStackTransform() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/tryCatchStackTransform.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultParameter extends AbstractIrCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInDefaultParameter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/defaultParameter"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("defaultValueCrossinline.kt")
public void testDefaultValueCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter/defaultValueCrossinline.kt");
doTest(fileName);
}
@TestMetadata("defaultValueInline.kt")
public void testDefaultValueInline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter/defaultValueInline.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Receiver extends AbstractIrCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInReceiver() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/receiver"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class StateMachine extends AbstractIrCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInStateMachine() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/stateMachine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("innerLambda.kt")
public void testInnerLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambda.kt");
doTest(fileName);
}
@TestMetadata("innerLambdaInsideLambda.kt")
public void testInnerLambdaInsideLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaInsideLambda.kt");
doTest(fileName);
}
@TestMetadata("innerLambdaWithoutCrossinline.kt")
public void testInnerLambdaWithoutCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaWithoutCrossinline.kt");
doTest(fileName);
}
@TestMetadata("innerMadness.kt")
public void testInnerMadness() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerMadness.kt");
doTest(fileName);
}
@TestMetadata("innerMadnessCallSite.kt")
public void testInnerMadnessCallSite() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerMadnessCallSite.kt");
doTest(fileName);
}
@TestMetadata("innerObject.kt")
public void testInnerObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObject.kt");
doTest(fileName);
}
@TestMetadata("innerObjectInsideInnerObject.kt")
public void testInnerObjectInsideInnerObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectInsideInnerObject.kt");
doTest(fileName);
}
@TestMetadata("innerObjectSeveralFunctions.kt")
public void testInnerObjectSeveralFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectSeveralFunctions.kt");
doTest(fileName);
}
@TestMetadata("innerObjectWithoutCapturingCrossinline.kt")
public void testInnerObjectWithoutCapturingCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectWithoutCapturingCrossinline.kt");
doTest(fileName);
}
@TestMetadata("normalInline.kt")
public void testNormalInline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/normalInline.kt");
doTest(fileName);
}
@TestMetadata("numberOfSuspentions.kt")
public void testNumberOfSuspentions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/numberOfSuspentions.kt");
doTest(fileName);
}
}
}
@TestMetadata("compiler/testData/codegen/boxInline/syntheticAccessors") @TestMetadata("compiler/testData/codegen/boxInline/syntheticAccessors")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1551,6 +1551,93 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
} }
} }
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineCrossinline extends AbstractDiagnosticsTestWithStdLib {
public void testAllFilesPresentInInlineCrossinline() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("crossinlineSuspendValueParameter.kt")
public void testCrossinlineSuspendValueParameter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/crossinlineSuspendValueParameter.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfCrossinlineOrdinary.kt")
public void testInlineOrdinaryOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineOrdinary.kt")
public void testInlineOrdinaryOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfOrdinary.kt")
public void testInlineOrdinaryOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfSuspend.kt")
public void testInlineOrdinaryOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension") @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -1551,6 +1551,93 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
} }
} }
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InlineCrossinline extends AbstractDiagnosticsTestWithStdLibUsingJavac {
public void testAllFilesPresentInInlineCrossinline() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("crossinlineSuspendValueParameter.kt")
public void testCrossinlineSuspendValueParameter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/crossinlineSuspendValueParameter.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfCrossinlineOrdinary.kt")
public void testInlineOrdinaryOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineOrdinary.kt")
public void testInlineOrdinaryOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfOrdinary.kt")
public void testInlineOrdinaryOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfSuspend.kt")
public void testInlineOrdinaryOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension") @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -3391,6 +3391,252 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
} }
} }
@TestMetadata("compiler/testData/codegen/boxInline/suspend")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Suspend extends AbstractBlackBoxInlineCodegenTest {
public void testAllFilesPresentInSuspend() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("capturedVariables.kt")
public void testCapturedVariables() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/capturedVariables.kt");
doTest(fileName);
}
@TestMetadata("crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt")
public void testCrossinlineSuspendLambdaInsideCrossinlineSuspendLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendContinuation.kt")
public void testInlineSuspendContinuation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendContinuation.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
@TestMetadata("multipleLocals.kt")
public void testMultipleLocals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/multipleLocals.kt");
doTest(fileName);
}
@TestMetadata("multipleSuspensionPoints.kt")
public void testMultipleSuspensionPoints() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/multipleSuspensionPoints.kt");
doTest(fileName);
}
@TestMetadata("tryCatchStackTransform.kt")
public void testTryCatchStackTransform() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/tryCatchStackTransform.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultParameter extends AbstractBlackBoxInlineCodegenTest {
public void testAllFilesPresentInDefaultParameter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/defaultParameter"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("defaultValueCrossinline.kt")
public void testDefaultValueCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter/defaultValueCrossinline.kt");
doTest(fileName);
}
@TestMetadata("defaultValueInline.kt")
public void testDefaultValueInline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter/defaultValueInline.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Receiver extends AbstractBlackBoxInlineCodegenTest {
public void testAllFilesPresentInReceiver() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/receiver"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class StateMachine extends AbstractBlackBoxInlineCodegenTest {
public void testAllFilesPresentInStateMachine() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/stateMachine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("innerLambda.kt")
public void testInnerLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambda.kt");
doTest(fileName);
}
@TestMetadata("innerLambdaInsideLambda.kt")
public void testInnerLambdaInsideLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaInsideLambda.kt");
doTest(fileName);
}
@TestMetadata("innerLambdaWithoutCrossinline.kt")
public void testInnerLambdaWithoutCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaWithoutCrossinline.kt");
doTest(fileName);
}
@TestMetadata("innerMadness.kt")
public void testInnerMadness() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerMadness.kt");
doTest(fileName);
}
@TestMetadata("innerMadnessCallSite.kt")
public void testInnerMadnessCallSite() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerMadnessCallSite.kt");
doTest(fileName);
}
@TestMetadata("innerObject.kt")
public void testInnerObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObject.kt");
doTest(fileName);
}
@TestMetadata("innerObjectInsideInnerObject.kt")
public void testInnerObjectInsideInnerObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectInsideInnerObject.kt");
doTest(fileName);
}
@TestMetadata("innerObjectSeveralFunctions.kt")
public void testInnerObjectSeveralFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectSeveralFunctions.kt");
doTest(fileName);
}
@TestMetadata("innerObjectWithoutCapturingCrossinline.kt")
public void testInnerObjectWithoutCapturingCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectWithoutCapturingCrossinline.kt");
doTest(fileName);
}
@TestMetadata("normalInline.kt")
public void testNormalInline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/normalInline.kt");
doTest(fileName);
}
@TestMetadata("numberOfSuspentions.kt")
public void testNumberOfSuspentions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/numberOfSuspentions.kt");
doTest(fileName);
}
}
}
@TestMetadata("compiler/testData/codegen/boxInline/syntheticAccessors") @TestMetadata("compiler/testData/codegen/boxInline/syntheticAccessors")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -3391,6 +3391,252 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
} }
} }
@TestMetadata("compiler/testData/codegen/boxInline/suspend")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Suspend extends AbstractCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInSuspend() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("capturedVariables.kt")
public void testCapturedVariables() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/capturedVariables.kt");
doTest(fileName);
}
@TestMetadata("crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt")
public void testCrossinlineSuspendLambdaInsideCrossinlineSuspendLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/crossinlineSuspendLambdaInsideCrossinlineSuspendLambda.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendContinuation.kt")
public void testInlineSuspendContinuation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendContinuation.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
@TestMetadata("multipleLocals.kt")
public void testMultipleLocals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/multipleLocals.kt");
doTest(fileName);
}
@TestMetadata("multipleSuspensionPoints.kt")
public void testMultipleSuspensionPoints() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/multipleSuspensionPoints.kt");
doTest(fileName);
}
@TestMetadata("tryCatchStackTransform.kt")
public void testTryCatchStackTransform() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/tryCatchStackTransform.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultParameter extends AbstractCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInDefaultParameter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/defaultParameter"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("defaultValueCrossinline.kt")
public void testDefaultValueCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter/defaultValueCrossinline.kt");
doTest(fileName);
}
@TestMetadata("defaultValueInline.kt")
public void testDefaultValueInline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/defaultParameter/defaultValueInline.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/receiver")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Receiver extends AbstractCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInReceiver() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/receiver"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineOrdinaryOfCrossinlineSuspend.kt")
public void testInlineOrdinaryOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineOrdinaryOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineOrdinaryOfNoinlineSuspend.kt")
public void testInlineOrdinaryOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineOrdinaryOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineOrdinary.kt")
public void testInlineSuspendOfCrossinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfCrossinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfCrossinlineSuspend.kt")
public void testInlineSuspendOfCrossinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfCrossinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineOrdinary.kt")
public void testInlineSuspendOfNoinlineOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfNoinlineSuspend.kt")
public void testInlineSuspendOfNoinlineSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfNoinlineSuspend.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfOrdinary.kt")
public void testInlineSuspendOfOrdinary() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfOrdinary.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendOfSuspend.kt")
public void testInlineSuspendOfSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/receiver/inlineSuspendOfSuspend.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class StateMachine extends AbstractCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInStateMachine() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/suspend/stateMachine"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("innerLambda.kt")
public void testInnerLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambda.kt");
doTest(fileName);
}
@TestMetadata("innerLambdaInsideLambda.kt")
public void testInnerLambdaInsideLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaInsideLambda.kt");
doTest(fileName);
}
@TestMetadata("innerLambdaWithoutCrossinline.kt")
public void testInnerLambdaWithoutCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerLambdaWithoutCrossinline.kt");
doTest(fileName);
}
@TestMetadata("innerMadness.kt")
public void testInnerMadness() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerMadness.kt");
doTest(fileName);
}
@TestMetadata("innerMadnessCallSite.kt")
public void testInnerMadnessCallSite() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerMadnessCallSite.kt");
doTest(fileName);
}
@TestMetadata("innerObject.kt")
public void testInnerObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObject.kt");
doTest(fileName);
}
@TestMetadata("innerObjectInsideInnerObject.kt")
public void testInnerObjectInsideInnerObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectInsideInnerObject.kt");
doTest(fileName);
}
@TestMetadata("innerObjectSeveralFunctions.kt")
public void testInnerObjectSeveralFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectSeveralFunctions.kt");
doTest(fileName);
}
@TestMetadata("innerObjectWithoutCapturingCrossinline.kt")
public void testInnerObjectWithoutCapturingCrossinline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/innerObjectWithoutCapturingCrossinline.kt");
doTest(fileName);
}
@TestMetadata("normalInline.kt")
public void testNormalInline() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/normalInline.kt");
doTest(fileName);
}
@TestMetadata("numberOfSuspentions.kt")
public void testNumberOfSuspentions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/suspend/stateMachine/numberOfSuspentions.kt");
doTest(fileName);
}
}
}
@TestMetadata("compiler/testData/codegen/boxInline/syntheticAccessors") @TestMetadata("compiler/testData/codegen/boxInline/syntheticAccessors")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)