Remove redundant locals
Do not transform already transformed suspend lambdas Ignore duplicates of continuation in local variable table during redundant locals elimination.
This commit is contained in:
@@ -1103,8 +1103,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
if (closure.isSuspend()) {
|
if (closure.isSuspend()) {
|
||||||
// resultContinuation
|
// resultContinuation
|
||||||
if (closure.isSuspendLambda()) {
|
if (closure.isSuspendLambda()) {
|
||||||
|
// When inlining crossinline lambda, the ACONST_NULL is never popped.
|
||||||
|
// Thus, do not generate it. Otherwise, it leads to VerifyError on run-time.
|
||||||
boolean isCrossinlineLambda = (callGenerator instanceof InlineCodegen<?>) &&
|
boolean isCrossinlineLambda = (callGenerator instanceof InlineCodegen<?>) &&
|
||||||
Objects.requireNonNull(((InlineCodegen) callGenerator).getActiveLambda()).isCrossInline;
|
Objects.requireNonNull(((InlineCodegen) callGenerator).getActiveLambda(),
|
||||||
|
"no active lambda found").isCrossInline;
|
||||||
if (!isCrossinlineLambda) {
|
if (!isCrossinlineLambda) {
|
||||||
v.aconst(null);
|
v.aconst(null);
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-44
@@ -70,6 +70,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
|
|
||||||
private final Stack<ClassDescriptor> classStack = new Stack<>();
|
private final Stack<ClassDescriptor> classStack = new Stack<>();
|
||||||
private final Stack<String> nameStack = new Stack<>();
|
private final Stack<String> nameStack = new Stack<>();
|
||||||
|
private final Stack<FunctionDescriptor> functionsStack = new Stack<>();
|
||||||
private final Set<ClassDescriptor> uninitializedClasses = new HashSet<>();
|
private final Set<ClassDescriptor> uninitializedClasses = new HashSet<>();
|
||||||
|
|
||||||
private final BindingTrace bindingTrace;
|
private final BindingTrace bindingTrace;
|
||||||
@@ -317,49 +318,16 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
);
|
);
|
||||||
closure.setSuspend(true);
|
closure.setSuspend(true);
|
||||||
closure.setSuspendLambda();
|
closure.setSuspendLambda();
|
||||||
if (capturesCrossinlineSuspendLambda(functionLiteral)) {
|
|
||||||
bindingTrace.record(
|
|
||||||
CodegenBinding.CAPTURES_CROSSINLINE_SUSPEND_LAMBDA,
|
|
||||||
functionDescriptor,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
functionsStack.push(functionDescriptor);
|
||||||
|
|
||||||
super.visitLambdaExpression(lambdaExpression);
|
super.visitLambdaExpression(lambdaExpression);
|
||||||
|
|
||||||
|
functionsStack.pop();
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
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);
|
||||||
@@ -573,17 +541,11 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
recordClassForFunction(function, functionDescriptor, name, functionDescriptor);
|
recordClassForFunction(function, functionDescriptor, name, functionDescriptor);
|
||||||
MutableClosure closure = recordClosure(classDescriptor, name);
|
MutableClosure closure = recordClosure(classDescriptor, name);
|
||||||
closure.setSuspend(true);
|
closure.setSuspend(true);
|
||||||
|
functionsStack.push(functionDescriptor);
|
||||||
if (capturesCrossinlineSuspendLambda(function)) {
|
|
||||||
bindingTrace.record(
|
|
||||||
CodegenBinding.CAPTURES_CROSSINLINE_SUSPEND_LAMBDA,
|
|
||||||
functionDescriptor,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.visitNamedFunction(function);
|
super.visitNamedFunction(function);
|
||||||
|
|
||||||
|
functionsStack.pop();
|
||||||
if (nameForClassOrPackageMember != null) {
|
if (nameForClassOrPackageMember != null) {
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
}
|
}
|
||||||
@@ -593,7 +555,9 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
|
|
||||||
if (nameForClassOrPackageMember != null) {
|
if (nameForClassOrPackageMember != null) {
|
||||||
nameStack.push(nameForClassOrPackageMember);
|
nameStack.push(nameForClassOrPackageMember);
|
||||||
|
functionsStack.push(functionDescriptor);
|
||||||
super.visitNamedFunction(function);
|
super.visitNamedFunction(function);
|
||||||
|
functionsStack.pop();
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -602,8 +566,10 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
recordClosure(classDescriptor, name);
|
recordClosure(classDescriptor, name);
|
||||||
|
|
||||||
classStack.push(classDescriptor);
|
classStack.push(classDescriptor);
|
||||||
|
functionsStack.push(functionDescriptor);
|
||||||
nameStack.push(name);
|
nameStack.push(name);
|
||||||
super.visitNamedFunction(function);
|
super.visitNamedFunction(function);
|
||||||
|
functionsStack.pop();
|
||||||
nameStack.pop();
|
nameStack.pop();
|
||||||
classStack.pop();
|
classStack.pop();
|
||||||
}
|
}
|
||||||
@@ -631,6 +597,47 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
public void visitCallExpression(@NotNull KtCallExpression expression) {
|
public void visitCallExpression(@NotNull KtCallExpression expression) {
|
||||||
super.visitCallExpression(expression);
|
super.visitCallExpression(expression);
|
||||||
checkSamCall(expression);
|
checkSamCall(expression);
|
||||||
|
checkCrossinlineSuspendCall(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkCrossinlineSuspendCall(@NotNull KtCallExpression expression) {
|
||||||
|
KtExpression callee = expression.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());
|
||||||
|
if (enclosingDescriptor == null) return;
|
||||||
|
|
||||||
|
DeclarationDescriptor functionWithCrossinlineParameter = variableDescriptor.getContainingDeclaration();
|
||||||
|
for (int i = functionsStack.size() - 1; i >= 0; i--) {
|
||||||
|
if (functionsStack.get(i).isSuspend()) {
|
||||||
|
Boolean alreadyPutValue = bindingTrace.getBindingContext()
|
||||||
|
.get(CodegenBinding.CAPTURES_CROSSINLINE_SUSPEND_LAMBDA, functionsStack.get(i));
|
||||||
|
if (alreadyPutValue != null && alreadyPutValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bindingTrace.record(
|
||||||
|
CodegenBinding.CAPTURES_CROSSINLINE_SUSPEND_LAMBDA,
|
||||||
|
functionsStack.get(i),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (functionsStack.get(i) == functionWithCrossinlineParameter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSamCall(@NotNull KtCallElement expression) {
|
private void checkSamCall(@NotNull KtCallElement expression) {
|
||||||
|
|||||||
+10
-8
@@ -67,20 +67,24 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
override fun performTransformations(methodNode: MethodNode) {
|
override fun performTransformations(methodNode: MethodNode) {
|
||||||
removeFakeContinuationConstructorCall(methodNode)
|
removeFakeContinuationConstructorCall(methodNode)
|
||||||
|
|
||||||
|
replaceFakeContinuationsWithRealOnes(
|
||||||
|
methodNode,
|
||||||
|
if (isForNamedFunction) getLastParameterIndex(methodNode.desc, methodNode.access) else 0
|
||||||
|
)
|
||||||
|
|
||||||
|
FixStackMethodTransformer().transform(containingClassInternalName, methodNode)
|
||||||
|
RedundantLocalsEliminationMethodTransformer().transform(containingClassInternalName, methodNode)
|
||||||
|
updateMaxStack(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
|
||||||
val actualCoroutineStart = methodNode.instructions.first
|
val actualCoroutineStart = methodNode.instructions.first
|
||||||
|
|
||||||
FixStackMethodTransformer().transform(containingClassInternalName, methodNode)
|
|
||||||
|
|
||||||
if (isForNamedFunction) {
|
if (isForNamedFunction) {
|
||||||
ReturnUnitMethodTransformer.transform(containingClassInternalName, methodNode)
|
ReturnUnitMethodTransformer.transform(containingClassInternalName, methodNode)
|
||||||
|
|
||||||
if (allSuspensionPointsAreTailCalls(containingClassInternalName, methodNode, suspensionPoints)) {
|
if (allSuspensionPointsAreTailCalls(containingClassInternalName, methodNode, suspensionPoints)) {
|
||||||
continuationIndex = getLastParameterIndex(methodNode.desc, methodNode.access)
|
|
||||||
replaceFakeContinuationsWithRealOnes(methodNode, continuationIndex)
|
|
||||||
|
|
||||||
dropSuspensionMarkers(methodNode, suspensionPoints)
|
dropSuspensionMarkers(methodNode, suspensionPoints)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -101,8 +105,6 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
// Actual max stack might be increased during the previous phases
|
// Actual max stack might be increased during the previous phases
|
||||||
updateMaxStack(methodNode)
|
updateMaxStack(methodNode)
|
||||||
|
|
||||||
replaceFakeContinuationsWithRealOnes(methodNode, continuationIndex)
|
|
||||||
|
|
||||||
// Remove unreachable suspension points
|
// Remove unreachable suspension points
|
||||||
// If we don't do this, then relevant frames will not be analyzed, that is unexpected from point of view of next steps (e.g. variable spilling)
|
// If we don't do this, then relevant frames will not be analyzed, that is unexpected from point of view of next steps (e.g. variable spilling)
|
||||||
removeUnreachableSuspensionPointsAndExitPoints(methodNode, suspensionPoints)
|
removeUnreachableSuspensionPointsAndExitPoints(methodNode, suspensionPoints)
|
||||||
@@ -820,7 +822,7 @@ 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) {
|
private fun replaceFakeContinuationsWithRealOnes(methodNode: MethodNode, continuationIndex: Int) {
|
||||||
val fakeContinuations = methodNode.instructions.asSequence().filter(::isFakeContinuationMarker).toList()
|
val fakeContinuations = methodNode.instructions.asSequence().filter(::isFakeContinuationMarker).toList()
|
||||||
for (fakeContinuation in fakeContinuations) {
|
for (fakeContinuation in fakeContinuations) {
|
||||||
methodNode.instructions.removeAll(listOf(fakeContinuation.previous.previous, fakeContinuation.previous))
|
methodNode.instructions.removeAll(listOf(fakeContinuation.previous.previous, fakeContinuation.previous))
|
||||||
|
|||||||
+218
@@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen.coroutines
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.boxing.isUnitInstance
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.common.ControlFlowGraph
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.common.removeAll
|
||||||
|
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
|
|
||||||
|
// Inliner emits a lot of locals during inlining.
|
||||||
|
// Remove all of them since these locals are
|
||||||
|
// 1) going to be spilled into continuation object
|
||||||
|
// 2) breaking tail-call elimination
|
||||||
|
class RedundantLocalsEliminationMethodTransformer : MethodTransformer() {
|
||||||
|
lateinit var internalClassName: String
|
||||||
|
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||||
|
this.internalClassName = internalClassName
|
||||||
|
do {
|
||||||
|
var changed = false
|
||||||
|
changed = simpleRemove(methodNode) || changed
|
||||||
|
changed = removeWithReplacement(methodNode) || changed
|
||||||
|
changed = removeAloadCheckcastContinuationAstore(methodNode) || changed
|
||||||
|
} while (changed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace
|
||||||
|
// GETSTATIC kotlin/Unit.INSTANCE
|
||||||
|
// ASTORE N
|
||||||
|
// ...
|
||||||
|
// ALOAD N
|
||||||
|
// with
|
||||||
|
// ...
|
||||||
|
// GETSTATIC kotlin/Unit.INSTANCE
|
||||||
|
// or
|
||||||
|
// ACONST_NULL
|
||||||
|
// ASTORE N
|
||||||
|
// ...
|
||||||
|
// ALOAD N
|
||||||
|
// with
|
||||||
|
// ...
|
||||||
|
// ACONST_NULL
|
||||||
|
// or
|
||||||
|
// ALOAD K
|
||||||
|
// ASTORE N
|
||||||
|
// ...
|
||||||
|
// ALOAD N
|
||||||
|
// with
|
||||||
|
// ...
|
||||||
|
// ALOAD K
|
||||||
|
//
|
||||||
|
// But do not remove several at a time, since the same local (for example, ALOAD 0) might be loaded and stored multiple times in
|
||||||
|
// sequence, like
|
||||||
|
// ALOAD 0
|
||||||
|
// ASTORE 1
|
||||||
|
// ALOAD 1
|
||||||
|
// ASTORE 2
|
||||||
|
// ALOAD 3
|
||||||
|
// Here, it is unsafe to replace ALOAD 3 with ALOAD 1, and then already removed ALOAD 1 with ALOAD 0.
|
||||||
|
private fun removeWithReplacement(
|
||||||
|
methodNode: MethodNode
|
||||||
|
): Boolean {
|
||||||
|
val insns = findSafeAstorePredecessors(methodNode, ignoreLocalVariableTable = false) {
|
||||||
|
it.isUnitInstance() || it.opcode == Opcodes.ACONST_NULL || it.opcode == Opcodes.ALOAD
|
||||||
|
}
|
||||||
|
insns.asIterable().firstOrNull { (pred, astore) ->
|
||||||
|
val index = astore.localIndex()
|
||||||
|
|
||||||
|
methodNode.instructions.removeAll(listOf(pred, astore))
|
||||||
|
|
||||||
|
methodNode.instructions.asSequence()
|
||||||
|
.filter { it.opcode == Opcodes.ALOAD && it.localIndex() == index }
|
||||||
|
.toList()
|
||||||
|
.forEach { methodNode.instructions.set(it, pred.clone()) }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun AbstractInsnNode.clone() = when (this) {
|
||||||
|
is FieldInsnNode -> FieldInsnNode(opcode, owner, name, desc)
|
||||||
|
is VarInsnNode -> VarInsnNode(opcode, `var`)
|
||||||
|
is InsnNode -> InsnNode(opcode)
|
||||||
|
is TypeInsnNode -> TypeInsnNode(opcode, desc)
|
||||||
|
else -> error("clone of $this is not implemented yet")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove
|
||||||
|
// ALOAD N
|
||||||
|
// POP
|
||||||
|
// or
|
||||||
|
// ACONST_NULL
|
||||||
|
// POP
|
||||||
|
// or
|
||||||
|
// GETSTATIC kotlin/Unit.INSTANCE
|
||||||
|
// POP
|
||||||
|
private fun simpleRemove(methodNode: MethodNode): Boolean {
|
||||||
|
val insns =
|
||||||
|
findPopPredecessors(methodNode) { it.isUnitInstance() || it.opcode == Opcodes.ACONST_NULL || it.opcode == Opcodes.ALOAD }
|
||||||
|
for ((pred, pop) in insns) {
|
||||||
|
methodNode.instructions.removeAll(listOf(pred, pop))
|
||||||
|
}
|
||||||
|
return insns.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findPopPredecessors(
|
||||||
|
methodNode: MethodNode,
|
||||||
|
predicate: (AbstractInsnNode) -> Boolean
|
||||||
|
): Map<AbstractInsnNode, AbstractInsnNode> {
|
||||||
|
val insns = methodNode.instructions.asSequence().filter { predicate(it) }.toList()
|
||||||
|
|
||||||
|
val cfg = ControlFlowGraph.build(methodNode)
|
||||||
|
|
||||||
|
val res = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
||||||
|
for (insn in insns) {
|
||||||
|
val succ = findImmediateSuccessors(insn, cfg, methodNode).singleOrNull() ?: continue
|
||||||
|
if (succ.opcode != Opcodes.POP) continue
|
||||||
|
if (insn.opcode == Opcodes.ALOAD && methodNode.localVariables.firstOrNull { it.index == insn.localIndex() } != null) continue
|
||||||
|
val sources = findSourceInstructions(internalClassName, methodNode, listOf(succ)).values.flatten()
|
||||||
|
if (sources.size != 1) continue
|
||||||
|
res[insn] = succ
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace
|
||||||
|
// ALOAD K
|
||||||
|
// CHECKCAST Continuation
|
||||||
|
// ASTORE N
|
||||||
|
// ...
|
||||||
|
// ALOAD N
|
||||||
|
// with
|
||||||
|
// ...
|
||||||
|
// ALOAD K
|
||||||
|
// CHECKCAST Continuation
|
||||||
|
private fun removeAloadCheckcastContinuationAstore(methodNode: MethodNode): Boolean {
|
||||||
|
// Here we ignore the duplicates of continuation in local variable table,
|
||||||
|
// Since it increases performance greatly.
|
||||||
|
val insns = findSafeAstorePredecessors(methodNode, ignoreLocalVariableTable = true) {
|
||||||
|
it.opcode == Opcodes.CHECKCAST &&
|
||||||
|
(it as TypeInsnNode).desc == CONTINUATION_ASM_TYPE.internalName &&
|
||||||
|
it.previous?.opcode == Opcodes.ALOAD
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((checkcast, astore) in insns) {
|
||||||
|
val aload = checkcast.previous
|
||||||
|
val index = astore.localIndex()
|
||||||
|
|
||||||
|
methodNode.instructions.removeAll(listOf(aload, checkcast, astore))
|
||||||
|
|
||||||
|
methodNode.instructions.asSequence()
|
||||||
|
.filter { it.opcode == Opcodes.ALOAD && it.localIndex() == index }
|
||||||
|
.toList()
|
||||||
|
.forEach {
|
||||||
|
methodNode.instructions.insertBefore(it, aload.clone())
|
||||||
|
methodNode.instructions.set(it, checkcast.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return insns.isNotEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findSafeAstorePredecessors(
|
||||||
|
methodNode: MethodNode,
|
||||||
|
ignoreLocalVariableTable: Boolean,
|
||||||
|
predicate: (AbstractInsnNode) -> Boolean
|
||||||
|
): Map<AbstractInsnNode, AbstractInsnNode> {
|
||||||
|
val insns = methodNode.instructions.asSequence().filter { predicate(it) }.toList()
|
||||||
|
|
||||||
|
val cfg = ControlFlowGraph.build(methodNode)
|
||||||
|
val res = hashMapOf<AbstractInsnNode, AbstractInsnNode>()
|
||||||
|
|
||||||
|
for (insn in insns) {
|
||||||
|
val succ = findImmediateSuccessors(insn, cfg, methodNode).singleOrNull() ?: continue
|
||||||
|
if (succ.opcode != Opcodes.ASTORE) continue
|
||||||
|
if (methodNode.instructions.asSequence().count {
|
||||||
|
it.opcode == Opcodes.ASTORE && it.localIndex() == succ.localIndex()
|
||||||
|
} != 1) continue
|
||||||
|
if (!ignoreLocalVariableTable && methodNode.localVariables.firstOrNull { it.index == succ.localIndex() } != null) continue
|
||||||
|
val sources = findSourceInstructions(internalClassName, methodNode, listOf(succ)).values.flatten()
|
||||||
|
if (sources.size > 1) continue
|
||||||
|
res[insn] = succ
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all meaningful successors of insn
|
||||||
|
private fun findImmediateSuccessors(
|
||||||
|
insn: AbstractInsnNode,
|
||||||
|
cfg: ControlFlowGraph,
|
||||||
|
methodNode: MethodNode
|
||||||
|
): Collection<AbstractInsnNode> {
|
||||||
|
val visited = hashSetOf<AbstractInsnNode>()
|
||||||
|
|
||||||
|
fun dfs(current: AbstractInsnNode): Collection<AbstractInsnNode> {
|
||||||
|
if (!visited.add(current)) return emptySet()
|
||||||
|
|
||||||
|
return cfg.getSuccessorsIndices(current).flatMap {
|
||||||
|
val succ = methodNode.instructions[it]
|
||||||
|
if (!succ.isMeaningful || succ is JumpInsnNode || succ.opcode == Opcodes.NOP) dfs(succ)
|
||||||
|
else setOf(succ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dfs(insn)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun AbstractInsnNode.localIndex(): Int {
|
||||||
|
assert(this is VarInsnNode)
|
||||||
|
return (this as VarInsnNode).`var`
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-13
@@ -106,19 +106,6 @@ object ReturnUnitMethodTransformer : MethodTransformer() {
|
|||||||
private fun isSuspendingCallReturningUnit(node: AbstractInsnNode): Boolean =
|
private fun isSuspendingCallReturningUnit(node: AbstractInsnNode): Boolean =
|
||||||
node.safeAs<MethodInsnNode>()?.next?.next?.let(::isReturnsUnitMarker) == true
|
node.safeAs<MethodInsnNode>()?.next?.next?.let(::isReturnsUnitMarker) == true
|
||||||
|
|
||||||
private fun findSourceInstructions(
|
|
||||||
internalClassName: String,
|
|
||||||
methodNode: MethodNode,
|
|
||||||
pops: Collection<AbstractInsnNode>
|
|
||||||
): Map<AbstractInsnNode, Collection<AbstractInsnNode>> {
|
|
||||||
val frames = analyze(internalClassName, methodNode, IgnoringCopyOperationSourceInterpreter())
|
|
||||||
return pops.keysToMap {
|
|
||||||
val index = methodNode.instructions.indexOf(it)
|
|
||||||
if (isUnreachable(index, frames)) return@keysToMap emptySet<AbstractInsnNode>()
|
|
||||||
frames[index].getStack(0).insns
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find { GETSTATIC kotlin/Unit.INSTANCE, ARETURN } sequences
|
// Find { GETSTATIC kotlin/Unit.INSTANCE, ARETURN } sequences
|
||||||
// Result is list of GETSTATIC kotlin/Unit.INSTANCE instructions
|
// Result is list of GETSTATIC kotlin/Unit.INSTANCE instructions
|
||||||
private fun findReturnUnitSequences(methodNode: MethodNode): Collection<AbstractInsnNode> =
|
private fun findReturnUnitSequences(methodNode: MethodNode): Collection<AbstractInsnNode> =
|
||||||
@@ -132,3 +119,15 @@ object ReturnUnitMethodTransformer : MethodTransformer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun findSourceInstructions(
|
||||||
|
internalClassName: String,
|
||||||
|
methodNode: MethodNode,
|
||||||
|
insns: Collection<AbstractInsnNode>
|
||||||
|
): Map<AbstractInsnNode, Collection<AbstractInsnNode>> {
|
||||||
|
val frames = MethodTransformer.analyze(internalClassName, methodNode, IgnoringCopyOperationSourceInterpreter())
|
||||||
|
return insns.keysToMap {
|
||||||
|
val index = methodNode.instructions.indexOf(it)
|
||||||
|
if (isUnreachable(index, frames)) return@keysToMap emptySet<AbstractInsnNode>()
|
||||||
|
frames[index].getStack(0).insns
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+8
-13
@@ -177,19 +177,14 @@ private fun NewResolvedCallImpl<VariableDescriptor>.asDummyOldResolvedCall(bindi
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun ResolvedCall<*>.isSuspendNoInlineCall(codegen: ExpressionCodegen): Boolean {
|
fun ResolvedCall<*>.isSuspendNoInlineCall(codegen: ExpressionCodegen): Boolean {
|
||||||
var isCrossinline = false
|
val isInlineLambda = this.safeAs<VariableAsFunctionResolvedCall>()
|
||||||
var isInlineLambda = false
|
?.variableCall?.resultingDescriptor?.safeAs<ValueParameterDescriptor>()
|
||||||
if (this is VariableAsFunctionResolvedCall) {
|
?.let { it.isCrossinline || (!it.isNoinline && codegen.context.functionDescriptor.isInline) } == true
|
||||||
variableCall.resultingDescriptor.safeAs<ValueParameterDescriptor>()?.let {
|
|
||||||
isCrossinline = it.isCrossinline
|
val functionDescriptor = resultingDescriptor as? FunctionDescriptor ?: return false
|
||||||
isInlineLambda = !isCrossinline && !it.isNoinline && codegen.context.functionDescriptor.isInline
|
if (!functionDescriptor.isSuspend) return false
|
||||||
}
|
if (functionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm() || functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm()) return true
|
||||||
}
|
return !(functionDescriptor.isInline || isInlineLambda)
|
||||||
return resultingDescriptor.safeAs<FunctionDescriptor>()
|
|
||||||
?.let {
|
|
||||||
val inline = it.isInline || isCrossinline || isInlineLambda
|
|
||||||
it.isSuspend && (!inline || it.isBuiltInSuspendCoroutineOrReturnInJvm() || it.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm())
|
|
||||||
} == true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean {
|
fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean {
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
|
|||||||
|
|
||||||
protected val expressionMap = linkedMapOf<Int, LambdaInfo>()
|
protected val expressionMap = linkedMapOf<Int, LambdaInfo>()
|
||||||
|
|
||||||
var activeLambda: LambdaInfo? = null; protected set
|
var activeLambda: LambdaInfo? = null
|
||||||
|
protected set
|
||||||
|
|
||||||
private val defaultSourceMapper = sourceCompiler.lazySourceMapper
|
private val defaultSourceMapper = sourceCompiler.lazySourceMapper
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ 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.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
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ class RegeneratedLambdaFieldRemapper(
|
|||||||
originalLambdaInternalName: String,
|
originalLambdaInternalName: String,
|
||||||
override val newLambdaInternalName: String,
|
override val newLambdaInternalName: String,
|
||||||
parameters: Parameters,
|
parameters: Parameters,
|
||||||
private val recapturedLambdas: Map<String, LambdaInfo>,
|
val recapturedLambdas: Map<String, LambdaInfo>,
|
||||||
remapper: FieldRemapper,
|
remapper: FieldRemapper,
|
||||||
private val isConstructor: Boolean
|
private val isConstructor: Boolean
|
||||||
) : FieldRemapper(originalLambdaInternalName, remapper, parameters) {
|
) : FieldRemapper(originalLambdaInternalName, remapper, parameters) {
|
||||||
|
|||||||
@@ -201,7 +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);
|
DiagnosticFactory0<PsiElement> 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);
|
||||||
|
|||||||
+2
-2
@@ -122,8 +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 supported. Add 'noinline' or 'crossinline' modifier.");
|
MAP.put(INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED, "Suspend inline lambda parameters of non-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(REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE, "Redundant 'suspend' modifier: lambda parameters of suspend function type uses existing continuation.");
|
||||||
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,
|
||||||
|
|||||||
@@ -17,13 +17,12 @@
|
|||||||
package org.jetbrains.kotlin.resolve.calls.checkers
|
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.isBuiltinFunctionalType
|
||||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.contracts.parsing.isFromContractDsl
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||||
import org.jetbrains.kotlin.contracts.parsing.isFromContractDsl
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
@@ -239,8 +238,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.isBuiltinFunctionalType
|
||||||
(containingDeclaration.defaultType.isFunctionType || containingDeclaration.defaultType.isSuspendFunctionType)
|
|
||||||
|
|
||||||
return isInvoke || InlineUtil.isInline(descriptor)
|
return isInvoke || InlineUtil.isInline(descriptor)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||||
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
import org.jetbrains.kotlin.psi.KtFunction
|
import org.jetbrains.kotlin.psi.KtFunction
|
||||||
@@ -32,7 +33,6 @@ 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)) {
|
||||||
@@ -43,8 +43,11 @@ object InlineParameterChecker : DeclarationChecker {
|
|||||||
!parameter.hasModifier(KtTokens.CROSSINLINE_KEYWORD) &&
|
!parameter.hasModifier(KtTokens.CROSSINLINE_KEYWORD) &&
|
||||||
parameterDescriptor?.type?.isSuspendFunctionType == true
|
parameterDescriptor?.type?.isSuspendFunctionType == true
|
||||||
) {
|
) {
|
||||||
if (suspend) {
|
if (declaration.hasModifier(KtTokens.SUSPEND_KEYWORD)) {
|
||||||
context.trace.report(Errors.REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE.on(parameter))
|
val typeReference = parameter.typeReference!!
|
||||||
|
val modifierList = typeReference.modifierList!!
|
||||||
|
val modifier = modifierList.getModifier(KtTokens.SUSPEND_KEYWORD)!!
|
||||||
|
context.trace.report(Errors.REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE.on(modifier))
|
||||||
} else {
|
} else {
|
||||||
context.trace.report(Errors.INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED.on(parameter))
|
context.trace.report(Errors.INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED.on(parameter))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ 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.isBuiltinFunctionalType(valueParameterOrReceiver.getOriginal().getType());
|
||||||
FunctionTypesKt.isSuspendFunctionType(valueParameterOrReceiver.getOriginal().getType()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInlineParameter(@NotNull ParameterDescriptor valueParameterOrReceiver) {
|
public static boolean isInlineParameter(@NotNull ParameterDescriptor valueParameterOrReceiver) {
|
||||||
|
|||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
// IGNORE_BACKEND: JS
|
||||||
|
// WITH_RUNTIME
|
||||||
|
// WITH_COROUTINES
|
||||||
|
// CHECK_BYTECODE_LISTING
|
||||||
|
import helpers.*
|
||||||
|
import kotlin.coroutines.experimental.*
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.*
|
||||||
|
|
||||||
|
interface SourceCrossinline<out E> {
|
||||||
|
suspend fun consume(sink: Sink<E>)
|
||||||
|
companion object Factory
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Sink<in E> {
|
||||||
|
suspend fun send(item: E)
|
||||||
|
fun close(cause: Throwable?)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <E> source(crossinline action: suspend Sink<E>.() -> Unit): SourceCrossinline<E> = object : SourceCrossinline<E> {
|
||||||
|
override suspend fun consume(sink: Sink<E>) {
|
||||||
|
var cause: Throwable? = null
|
||||||
|
try {
|
||||||
|
action(sink)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
cause = e
|
||||||
|
}
|
||||||
|
sink.close(cause)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SourceCrossinline.Factory.range(start: Int, count: Int): SourceCrossinline<Int> = source<Int> {
|
||||||
|
for (i in start until (start + count)) {
|
||||||
|
send(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend inline fun <E> SourceCrossinline<E>.consumeEach(crossinline action: suspend (E) -> Unit) {
|
||||||
|
consume(object : Sink<E> {
|
||||||
|
override suspend fun send(item: E) = action(item)
|
||||||
|
override fun close(cause: Throwable?) { cause?.let { throw it } }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend inline fun <E, R> SourceCrossinline<E>.fold(initial: R, crossinline operation: suspend (acc: R, E) -> R): R {
|
||||||
|
var acc = initial
|
||||||
|
consumeEach {
|
||||||
|
acc = operation(acc, it)
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <E> SourceCrossinline<E>.filter(crossinline predicate: (E) -> Boolean) = source<E> {
|
||||||
|
consumeEach {
|
||||||
|
if (predicate(it)) send(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder(c: suspend () -> Unit) {
|
||||||
|
c.startCoroutine(EmptyContinuation)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Int.isGood() = this % 4 == 0
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var res = 0
|
||||||
|
builder {
|
||||||
|
res = SourceCrossinline
|
||||||
|
.range(1, 11)
|
||||||
|
.filter { it.isGood() }
|
||||||
|
.fold(0, { a, b -> a + b })
|
||||||
|
}
|
||||||
|
if (res != 12) return "FAIL"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+352
@@ -0,0 +1,352 @@
|
|||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$doResume$$inlined$filter$1$1 {
|
||||||
|
field L$0: java.lang.Object
|
||||||
|
field L$1: java.lang.Object
|
||||||
|
field L$2: java.lang.Object
|
||||||
|
field L$3: java.lang.Object
|
||||||
|
field L$4: java.lang.Object
|
||||||
|
field L$5: java.lang.Object
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$box$1$doResume$$inlined$filter$1
|
||||||
|
inner class CrossinlineKt$box$1$doResume$$inlined$filter$1
|
||||||
|
inner class CrossinlineKt$box$1$doResume$$inlined$filter$1$1
|
||||||
|
public method <init>(p0: CrossinlineKt$box$1$doResume$$inlined$filter$1, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$doResume$$inlined$filter$1$2$1 {
|
||||||
|
field L$0: java.lang.Object
|
||||||
|
field L$1: java.lang.Object
|
||||||
|
field L$2: java.lang.Object
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$box$1$doResume$$inlined$filter$1$2
|
||||||
|
inner class CrossinlineKt$box$1$doResume$$inlined$filter$1$2
|
||||||
|
inner class CrossinlineKt$box$1$doResume$$inlined$filter$1$2$1
|
||||||
|
public method <init>(p0: CrossinlineKt$box$1$doResume$$inlined$filter$1$2, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$doResume$$inlined$filter$1$2 {
|
||||||
|
synthetic final field receiver$0$inlined: Sink
|
||||||
|
synthetic final field this$0: CrossinlineKt$box$1$doResume$$inlined$filter$1
|
||||||
|
inner class CrossinlineKt$box$1$doResume$$inlined$filter$1$2
|
||||||
|
inner class CrossinlineKt$box$1$doResume$$inlined$filter$1$2$1
|
||||||
|
public method <init>(p0: Sink, p1: CrossinlineKt$box$1$doResume$$inlined$filter$1): void
|
||||||
|
public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$doResume$$inlined$filter$1 {
|
||||||
|
synthetic final field receiver$0$inlined: SourceCrossinline
|
||||||
|
inner class CrossinlineKt$box$1$doResume$$inlined$filter$1
|
||||||
|
inner class CrossinlineKt$box$1$doResume$$inlined$filter$1$1
|
||||||
|
public method <init>(p0: SourceCrossinline): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$doResume$$inlined$fold$1 {
|
||||||
|
synthetic final field $acc$inlined: kotlin.jvm.internal.Ref$ObjectRef
|
||||||
|
inner class CrossinlineKt$box$1$doResume$$inlined$fold$1
|
||||||
|
inner class CrossinlineKt$box$1$fold$$inlined$consumeEach$1$1
|
||||||
|
public method <init>(p0: kotlin.jvm.internal.Ref$ObjectRef): void
|
||||||
|
public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$filter$$inlined$source$1$1 {
|
||||||
|
field L$0: java.lang.Object
|
||||||
|
field L$1: java.lang.Object
|
||||||
|
field L$2: java.lang.Object
|
||||||
|
field L$3: java.lang.Object
|
||||||
|
field L$4: java.lang.Object
|
||||||
|
field L$5: java.lang.Object
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$box$1$filter$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$box$1$filter$$inlined$source$1$1
|
||||||
|
public method <init>(p0: CrossinlineKt$box$1$filter$$inlined$source$1, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1 {
|
||||||
|
field L$0: java.lang.Object
|
||||||
|
field L$1: java.lang.Object
|
||||||
|
field L$2: java.lang.Object
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1
|
||||||
|
inner class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1
|
||||||
|
inner class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1
|
||||||
|
public method <init>(p0: CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1 {
|
||||||
|
synthetic final field receiver$0$inlined: Sink
|
||||||
|
synthetic final field this$0: CrossinlineKt$box$1$filter$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1
|
||||||
|
inner class CrossinlineKt$box$1$filter$$inlined$source$1$lambda$1$1
|
||||||
|
public method <init>(p0: Sink, p1: CrossinlineKt$box$1$filter$$inlined$source$1): void
|
||||||
|
public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$filter$$inlined$source$1 {
|
||||||
|
synthetic final field $predicate$inlined: kotlin.jvm.functions.Function1
|
||||||
|
synthetic final field receiver$0$inlined: SourceCrossinline
|
||||||
|
inner class CrossinlineKt$box$1$filter$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$box$1$filter$$inlined$source$1$1
|
||||||
|
public method <init>(p0: SourceCrossinline, p1: kotlin.jvm.functions.Function1): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$fold$$inlined$consumeEach$1$1 {
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$box$1$fold$$inlined$consumeEach$1
|
||||||
|
inner class CrossinlineKt$box$1$fold$$inlined$consumeEach$1
|
||||||
|
inner class CrossinlineKt$box$1$fold$$inlined$consumeEach$1$1
|
||||||
|
public method <init>(p0: CrossinlineKt$box$1$fold$$inlined$consumeEach$1, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$box$1$fold$$inlined$consumeEach$1 {
|
||||||
|
synthetic final field $acc$inlined: kotlin.jvm.internal.Ref$ObjectRef
|
||||||
|
synthetic final field $operation$inlined: kotlin.jvm.functions.Function3
|
||||||
|
inner class CrossinlineKt$box$1$fold$$inlined$consumeEach$1
|
||||||
|
inner class CrossinlineKt$box$1$fold$$inlined$consumeEach$1$1
|
||||||
|
public method <init>(p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.jvm.functions.Function3): void
|
||||||
|
public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
final class CrossinlineKt$box$1 {
|
||||||
|
synthetic final field $res: kotlin.jvm.internal.Ref$IntRef
|
||||||
|
field L$0: java.lang.Object
|
||||||
|
field L$1: java.lang.Object
|
||||||
|
field L$2: java.lang.Object
|
||||||
|
field L$3: java.lang.Object
|
||||||
|
field L$4: java.lang.Object
|
||||||
|
inner class CrossinlineKt$box$1
|
||||||
|
method <init>(p0: kotlin.jvm.internal.Ref$IntRef, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.NotNull method create(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): kotlin.coroutines.experimental.Continuation
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
public final @org.jetbrains.annotations.Nullable method invoke(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
public synthetic method invoke(p0: java.lang.Object): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$consumeEach$2$send$1 {
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$consumeEach$2
|
||||||
|
inner class CrossinlineKt$consumeEach$2
|
||||||
|
inner class CrossinlineKt$consumeEach$2$send$1
|
||||||
|
public method <init>(p0: CrossinlineKt$consumeEach$2, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$consumeEach$2 {
|
||||||
|
synthetic final field $action: kotlin.jvm.functions.Function2
|
||||||
|
inner class CrossinlineKt$consumeEach$2
|
||||||
|
inner class CrossinlineKt$consumeEach$2$send$1
|
||||||
|
public method <init>(p0: kotlin.jvm.functions.Function2): void
|
||||||
|
public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$filter$$inlined$source$1$1 {
|
||||||
|
field L$0: java.lang.Object
|
||||||
|
field L$1: java.lang.Object
|
||||||
|
field L$2: java.lang.Object
|
||||||
|
field L$3: java.lang.Object
|
||||||
|
field L$4: java.lang.Object
|
||||||
|
field L$5: java.lang.Object
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$filter$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$filter$$inlined$source$1$1
|
||||||
|
public method <init>(p0: CrossinlineKt$filter$$inlined$source$1, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$filter$$inlined$source$1$lambda$1$1 {
|
||||||
|
field L$0: java.lang.Object
|
||||||
|
field L$1: java.lang.Object
|
||||||
|
field L$2: java.lang.Object
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1$lambda$1
|
||||||
|
inner class CrossinlineKt$filter$$inlined$source$1$lambda$1
|
||||||
|
inner class CrossinlineKt$filter$$inlined$source$1$lambda$1$1
|
||||||
|
public method <init>(p0: CrossinlineKt$filter$$inlined$source$1$lambda$1, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$filter$$inlined$source$1$lambda$1 {
|
||||||
|
synthetic final field receiver$0$inlined: Sink
|
||||||
|
synthetic final field this$0: CrossinlineKt$filter$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$filter$$inlined$source$1$lambda$1
|
||||||
|
inner class CrossinlineKt$filter$$inlined$source$1$lambda$1$1
|
||||||
|
public method <init>(p0: Sink, p1: CrossinlineKt$filter$$inlined$source$1): void
|
||||||
|
public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$filter$$inlined$source$1 {
|
||||||
|
synthetic final field $predicate$inlined: kotlin.jvm.functions.Function1
|
||||||
|
synthetic final field receiver$0$inlined: SourceCrossinline
|
||||||
|
inner class CrossinlineKt$filter$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$filter$$inlined$source$1$1
|
||||||
|
public method <init>(p0: SourceCrossinline, p1: kotlin.jvm.functions.Function1): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$fold$$inlined$consumeEach$1$1 {
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$fold$$inlined$consumeEach$1
|
||||||
|
inner class CrossinlineKt$fold$$inlined$consumeEach$1
|
||||||
|
inner class CrossinlineKt$fold$$inlined$consumeEach$1$1
|
||||||
|
public method <init>(p0: CrossinlineKt$fold$$inlined$consumeEach$1, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$fold$$inlined$consumeEach$1 {
|
||||||
|
synthetic final field $acc$inlined: kotlin.jvm.internal.Ref$ObjectRef
|
||||||
|
synthetic final field $operation$inlined: kotlin.jvm.functions.Function3
|
||||||
|
inner class CrossinlineKt$fold$$inlined$consumeEach$1
|
||||||
|
inner class CrossinlineKt$fold$$inlined$consumeEach$1$1
|
||||||
|
public method <init>(p0: kotlin.jvm.internal.Ref$ObjectRef, p1: kotlin.jvm.functions.Function3): void
|
||||||
|
public method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$range$$inlined$source$1$1 {
|
||||||
|
field I$0: int
|
||||||
|
field I$1: int
|
||||||
|
field L$0: java.lang.Object
|
||||||
|
field L$1: java.lang.Object
|
||||||
|
field L$2: java.lang.Object
|
||||||
|
field L$3: java.lang.Object
|
||||||
|
field L$4: java.lang.Object
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$range$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$range$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$range$$inlined$source$1$1
|
||||||
|
public method <init>(p0: CrossinlineKt$range$$inlined$source$1, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$range$$inlined$source$1 {
|
||||||
|
synthetic final field $count$inlined: int
|
||||||
|
synthetic final field $start$inlined: int
|
||||||
|
inner class CrossinlineKt$range$$inlined$source$1
|
||||||
|
inner class CrossinlineKt$range$$inlined$source$1$1
|
||||||
|
public method <init>(p0: int, p1: int): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$source$1$consume$1 {
|
||||||
|
synthetic field data: java.lang.Object
|
||||||
|
synthetic field exception: java.lang.Throwable
|
||||||
|
synthetic final field this$0: CrossinlineKt$source$1
|
||||||
|
inner class CrossinlineKt$source$1
|
||||||
|
inner class CrossinlineKt$source$1$consume$1
|
||||||
|
public method <init>(p0: CrossinlineKt$source$1, p1: kotlin.coroutines.experimental.Continuation): void
|
||||||
|
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||||
|
synthetic final method getLabel(): int
|
||||||
|
synthetic final method setLabel(p0: int): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt$source$1 {
|
||||||
|
synthetic final field $action: kotlin.jvm.functions.Function2
|
||||||
|
inner class CrossinlineKt$source$1
|
||||||
|
inner class CrossinlineKt$source$1$consume$1
|
||||||
|
public method <init>(p0: kotlin.jvm.functions.Function2): void
|
||||||
|
public @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class CrossinlineKt {
|
||||||
|
inner class CrossinlineKt$box$1
|
||||||
|
inner class CrossinlineKt$consumeEach$2
|
||||||
|
inner class CrossinlineKt$source$1
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
|
||||||
|
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
|
||||||
|
private final static method consumeEach(@org.jetbrains.annotations.NotNull p0: SourceCrossinline, p1: kotlin.jvm.functions.Function2, p2: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method filter(@org.jetbrains.annotations.NotNull p0: SourceCrossinline, @org.jetbrains.annotations.NotNull p1: kotlin.jvm.functions.Function1): SourceCrossinline
|
||||||
|
private final static method fold(@org.jetbrains.annotations.NotNull p0: SourceCrossinline, p1: java.lang.Object, p2: kotlin.jvm.functions.Function3, p3: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
public final static method isGood(p0: int): boolean
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method range(@org.jetbrains.annotations.NotNull p0: SourceCrossinline$Factory, p1: int, p2: int): SourceCrossinline
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method source(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function2): SourceCrossinline
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public interface Sink {
|
||||||
|
public abstract method close(@org.jetbrains.annotations.Nullable p0: java.lang.Throwable): void
|
||||||
|
public abstract @org.jetbrains.annotations.Nullable method send(p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class SourceCrossinline$Factory {
|
||||||
|
synthetic final static field $$INSTANCE: SourceCrossinline$Factory
|
||||||
|
inner class SourceCrossinline$Factory
|
||||||
|
static method <clinit>(): void
|
||||||
|
private method <init>(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public interface SourceCrossinline {
|
||||||
|
public final static field Factory: SourceCrossinline$Factory
|
||||||
|
inner class SourceCrossinline$Factory
|
||||||
|
static method <clinit>(): void
|
||||||
|
public abstract @org.jetbrains.annotations.Nullable method consume(@org.jetbrains.annotations.NotNull p0: Sink, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||||
|
}
|
||||||
Vendored
-1
@@ -14,7 +14,6 @@ final class InlineWithoutStateMachineKt$box$1 {
|
|||||||
@kotlin.Metadata
|
@kotlin.Metadata
|
||||||
final class InlineWithoutStateMachineKt$complexSuspend$1 {
|
final class InlineWithoutStateMachineKt$complexSuspend$1 {
|
||||||
field L$0: java.lang.Object
|
field L$0: java.lang.Object
|
||||||
field L$1: java.lang.Object
|
|
||||||
synthetic field data: java.lang.Object
|
synthetic field data: java.lang.Object
|
||||||
synthetic field exception: java.lang.Throwable
|
synthetic field exception: java.lang.Throwable
|
||||||
inner class InlineWithoutStateMachineKt$complexSuspend$1
|
inner class InlineWithoutStateMachineKt$complexSuspend$1
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ suspend inline fun test2(crossinline c: suspend () -> Unit) {
|
|||||||
// FILE: box.kt
|
// FILE: box.kt
|
||||||
|
|
||||||
import kotlin.coroutines.experimental.*
|
import kotlin.coroutines.experimental.*
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.*
|
||||||
|
|
||||||
fun builder(c: suspend () -> Unit) {
|
fun builder(c: suspend () -> Unit) {
|
||||||
c.startCoroutine(object: Continuation<Unit> {
|
c.startCoroutine(object: Continuation<Unit> {
|
||||||
@@ -30,7 +31,10 @@ fun builder(c: suspend () -> Unit) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun calculate() = "OK"
|
suspend fun calculate() = suspendCoroutineOrReturn<String> {
|
||||||
|
it.resume("OK")
|
||||||
|
COROUTINE_SUSPENDED
|
||||||
|
}
|
||||||
|
|
||||||
fun box() : String {
|
fun box() : String {
|
||||||
var res = "FAIL 1"
|
var res = "FAIL 1"
|
||||||
|
|||||||
@@ -25,5 +25,8 @@ fun box() : String {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When we generate code of suspend function returning unit call
|
||||||
|
// we surround it with return unit markers.
|
||||||
|
// While denerating state machine, we remove them.
|
||||||
// 0 ICONST_2
|
// 0 ICONST_2
|
||||||
// 0 ICONST_3
|
// 0 ICONST_3
|
||||||
-2
@@ -1,2 +0,0 @@
|
|||||||
// SKIP_TXT
|
|
||||||
inline fun foo(crossinline <!WRONG_MODIFIER_TARGET!>suspend<!> <!UNUSED_PARAMETER!>c<!>: () -> Unit) {}
|
|
||||||
compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineSuspendOfSuspend.kt
Vendored
+1
-1
@@ -20,7 +20,7 @@ interface SuspendRunnable {
|
|||||||
// Block is NOT allowed to be called from nested classes/lambdas (as common crossinlines)
|
// Block is NOT allowed to be called from nested classes/lambdas (as common crossinlines)
|
||||||
// It is NOT possible to call startCoroutine on the parameter
|
// It is NOT possible to call startCoroutine on the parameter
|
||||||
// suspend calls possible inside lambda matching to the parameter
|
// suspend calls possible inside lambda matching to the parameter
|
||||||
suspend inline fun test(<!REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE!>c: suspend () -> Unit<!>) {
|
suspend inline fun test(c: <!REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE!>suspend<!> () -> Unit) {
|
||||||
c()
|
c()
|
||||||
val o = object: SuspendRunnable {
|
val o = object: SuspendRunnable {
|
||||||
override suspend fun run() {
|
override suspend fun run() {
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ 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(<!REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE!>x: suspend () -> Unit<!>) {}
|
suspend inline fun bar1(x: <!REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE!>suspend<!> () -> Unit) {}
|
||||||
suspend inline fun bar2(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) {}
|
||||||
|
|||||||
Generated
+6
@@ -6683,6 +6683,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("crossinline.kt")
|
||||||
|
public void testCrossinline() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inlineWithStateMachine.kt")
|
@TestMetadata("inlineWithStateMachine.kt")
|
||||||
public void testInlineWithStateMachine() throws Exception {
|
public void testInlineWithStateMachine() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt");
|
||||||
|
|||||||
-6
@@ -1559,12 +1559,6 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
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")
|
@TestMetadata("inlineOrdinaryOfCrossinlineOrdinary.kt")
|
||||||
public void testInlineOrdinaryOfCrossinlineOrdinary() throws Exception {
|
public void testInlineOrdinaryOfCrossinlineOrdinary() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfCrossinlineOrdinary.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfCrossinlineOrdinary.kt");
|
||||||
|
|||||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
-6
@@ -1559,12 +1559,6 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
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")
|
@TestMetadata("inlineOrdinaryOfCrossinlineOrdinary.kt")
|
||||||
public void testInlineOrdinaryOfCrossinlineOrdinary() throws Exception {
|
public void testInlineOrdinaryOfCrossinlineOrdinary() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfCrossinlineOrdinary.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/inlineCrossinline/inlineOrdinaryOfCrossinlineOrdinary.kt");
|
||||||
|
|||||||
+6
@@ -6683,6 +6683,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("crossinline.kt")
|
||||||
|
public void testCrossinline() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inlineWithStateMachine.kt")
|
@TestMetadata("inlineWithStateMachine.kt")
|
||||||
public void testInlineWithStateMachine() throws Exception {
|
public void testInlineWithStateMachine() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt");
|
||||||
|
|||||||
+6
@@ -6683,6 +6683,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("crossinline.kt")
|
||||||
|
public void testCrossinline() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inlineWithStateMachine.kt")
|
@TestMetadata("inlineWithStateMachine.kt")
|
||||||
public void testInlineWithStateMachine() throws Exception {
|
public void testInlineWithStateMachine() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt");
|
||||||
|
|||||||
+12
@@ -7253,6 +7253,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/tailCallOptimizations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("crossinline.kt")
|
||||||
|
public void testCrossinline() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/crossinline.kt");
|
||||||
|
try {
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("inlineWithStateMachine.kt")
|
@TestMetadata("inlineWithStateMachine.kt")
|
||||||
public void testInlineWithStateMachine() throws Exception {
|
public void testInlineWithStateMachine() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user