Support finnaly blocks from inline fun in non-local returns

This commit is contained in:
max.kammerer
2014-07-22 13:54:41 +04:00
committed by Michael Bogdanov
parent 309329afd0
commit 9564eaa6fd
55 changed files with 3708 additions and 70 deletions
@@ -40,10 +40,7 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.commons.Method;
@@ -705,12 +702,12 @@ public class AsmUtil {
return expectedType;
}
public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) {
public static void pop(@NotNull MethodVisitor v, @NotNull Type type) {
if (type.getSize() == 2) {
v.pop2();
v.visitInsn(Opcodes.POP2);
}
else {
v.pop();
v.visitInsn(Opcodes.POP);
}
}
@@ -47,12 +47,8 @@ import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.Method;
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
import org.jetbrains.org.objectweb.asm.util.Textifier;
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
@@ -130,7 +126,7 @@ public class InlineCodegen implements CallGenerator {
throw new CompilationException("Couldn't inline method call '" +
functionDescriptor.getName() +
"' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) +
(generateNodeText ? ("\ncause: " + getNodeText(node)) : ""),
(generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(node)) : ""),
e, callElement);
}
@@ -242,7 +238,7 @@ public class InlineCodegen implements CallGenerator {
}
}
};
List<MethodInliner.FinallyBlockInfo> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
List<MethodInliner.ExternalFinallyBlockInfo> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
generateAndInsertFinallyBlocks(adapter, infos);
adapter.accept(new InliningInstructionAdapter(codegen.v));
@@ -443,19 +439,6 @@ public class InlineCodegen implements CallGenerator {
return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0;
}
@NotNull
public static String getNodeText(@Nullable MethodNode node) {
if (node == null) {
return "Not generated";
}
Textifier p = new Textifier();
node.accept(new TraceMethodVisitor(p));
StringWriter sw = new StringWriter();
p.print(new PrintWriter(sw));
sw.flush();
return node.name + " " + node.desc + ": \n " + sw.getBuffer().toString();
}
private static String descriptorName(DeclarationDescriptor descriptor) {
return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
}
@@ -494,10 +477,10 @@ public class InlineCodegen implements CallGenerator {
}
public void generateAndInsertFinallyBlocks(MethodNode intoNode, List<MethodInliner.FinallyBlockInfo> insertPoints) {
public void generateAndInsertFinallyBlocks(MethodNode intoNode, List<MethodInliner.ExternalFinallyBlockInfo> insertPoints) {
if (!codegen.hasFinallyBlocks()) return;
for (MethodInliner.FinallyBlockInfo insertPoint : insertPoints) {
for (MethodInliner.ExternalFinallyBlockInfo insertPoint : insertPoints) {
MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
ExpressionCodegen finallyCodegen =
new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(),
@@ -16,13 +16,13 @@
package org.jetbrains.jet.codegen.inline;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.codegen.binding.CodegenBinding;
import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.context.PackageContext;
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.kotlin.DeserializedResolverUtils;
@@ -44,12 +45,14 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
import org.jetbrains.org.objectweb.asm.tree.InsnList;
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
import org.jetbrains.org.objectweb.asm.tree.*;
import org.jetbrains.org.objectweb.asm.util.Textifier;
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.ListIterator;
@@ -283,6 +286,13 @@ public class InlineCodegenUtil {
return opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN;
}
//marked return could be either non-local or local in case of labeled lambda self-returns
public static boolean isMarkedReturn(@NotNull AbstractInsnNode returnIns) {
assert isReturnOpcode(returnIns.getOpcode()) : "Should be called on return instruction, but " + returnIns;
AbstractInsnNode globalFlag = returnIns.getPrevious();
return globalFlag instanceof MethodInsnNode && NON_LOCAL_RETURN.equals(((MethodInsnNode)globalFlag).owner);
}
public static void generateGlobalReturnFlag(@NotNull InstructionAdapter iv, @NotNull String labelName) {
iv.invokestatic(NON_LOCAL_RETURN, labelName, "()V", false);
}
@@ -294,16 +304,16 @@ public class InlineCodegenUtil {
case Opcodes.DRETURN: return Type.DOUBLE_TYPE;
case Opcodes.FRETURN: return Type.FLOAT_TYPE;
case Opcodes.LRETURN: return Type.LONG_TYPE;
default: return Type.getObjectType("object");
default: return AsmTypeConstants.OBJECT_TYPE;
}
}
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull MethodNode to, @NotNull AbstractInsnNode afterNode) {
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull MethodNode to, @NotNull AbstractInsnNode beforeNode) {
InsnList instructions = to.instructions;
ListIterator<AbstractInsnNode> iterator = from.instructions.iterator();
while (iterator.hasNext()) {
AbstractInsnNode next = iterator.next();
instructions.insertBefore(afterNode, next);
instructions.insertBefore(beforeNode, next);
}
}
@@ -311,4 +321,60 @@ public class InlineCodegenUtil {
public static MethodNode createEmptyMethodNode() {
return new MethodNode(API, 0, "fake", "()V", null, null);
}
private static boolean isLastGoto(@NotNull AbstractInsnNode insnNode, @NotNull AbstractInsnNode stopAt) {
if (insnNode.getOpcode() == Opcodes.GOTO) {
insnNode = insnNode.getNext();
while (insnNode != stopAt && isLineNumberOrLabel(insnNode)) {
insnNode = insnNode.getNext();
}
return stopAt == insnNode;
}
return false;
}
static boolean isLineNumberOrLabel(@Nullable AbstractInsnNode node) {
return node instanceof LineNumberNode || node instanceof LabelNode;
}
@NotNull
public static LabelNode firstLabelInChain(@NotNull LabelNode node) {
LabelNode curNode = node;
while (curNode.getPrevious() instanceof LabelNode) {
curNode = (LabelNode) curNode.getPrevious();
}
return curNode;
}
@NotNull
public static String getNodeText(@Nullable MethodNode node) {
return getNodeText(node, new Textifier());
}
@NotNull
public static String getNodeText(@Nullable MethodNode node, @NotNull Textifier textifier) {
if (node == null) {
return "Not generated";
}
node.accept(new TraceMethodVisitor(textifier));
StringWriter sw = new StringWriter();
textifier.print(new PrintWriter(sw));
sw.flush();
return node.name + " " + node.desc + ": \n " + sw.getBuffer().toString();
}
public static class LabelTextifier extends Textifier {
public LabelTextifier() {
super(API);
}
@Nullable
@TestOnly
@SuppressWarnings("UnusedDeclaration")
public String getLabelNameIfExists(@NotNull Label l) {
return labelNames == null ? null : labelNames.get(l);
}
}
}
@@ -0,0 +1,456 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.codegen.inline;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.AsmUtil;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.tree.*;
import java.util.*;
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.*;
public class InternalFinallyBlockInliner {
private static class FinallyBlockInfo {
final AbstractInsnNode startIns;
final AbstractInsnNode endInsExclusive;
private FinallyBlockInfo(@NotNull AbstractInsnNode inclusiveStart, @NotNull AbstractInsnNode exclusiveEnd) {
startIns = inclusiveStart;
endInsExclusive = exclusiveEnd;
}
}
public static void processInlineFunFinallyBlocks(@NotNull MethodNode inlineFun, int lambdaTryCatchBlockNodes) {
int index = 0;
List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo = new ArrayList<TryCatchBlockNodeInfo>();
for (TryCatchBlockNode block : inlineFun.tryCatchBlocks) {
inlineFunTryBlockInfo.add(new TryCatchBlockNodeInfo(block, index++ < lambdaTryCatchBlockNodes));
}
if (hasFinallyBlocks(inlineFunTryBlockInfo)) {
new InternalFinallyBlockInliner(inlineFun, inlineFunTryBlockInfo).processInlineFunFinallyBlocks();
}
}
@NotNull
private final MethodNode inlineFun;
private final List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo;
private final ListMultimap<LabelNode, TryCatchBlockNodeInfo> tryBlockStarts = LinkedListMultimap.create();
private final ListMultimap<LabelNode, TryCatchBlockNodeInfo> tryBlockEnds = LinkedListMultimap.create();
//lambdaTryCatchBlockNodes is number of TryCatchBlockNodes that was inlined with lambdas into function
//due to code generation specific they placed before function TryCatchBlockNodes
private InternalFinallyBlockInliner(@NotNull MethodNode inlineFun, List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo) {
this.inlineFun = inlineFun;
this.inlineFunTryBlockInfo = inlineFunTryBlockInfo;
}
private int initAndGetVarIndexForNonLocalReturnValue() {
//sortTryCatchBlocks();/*TODO maybe remove*/
mapLabelsToTryCatchBlocks();
MaxCalcNode tempCalcNode = new MaxCalcNode(inlineFun.desc, (inlineFun.access & Opcodes.ACC_STATIC) != 0);
inlineFun.accept(tempCalcNode);
return tempCalcNode.getMaxLocal();
}
private void processInlineFunFinallyBlocks() {
int nextTempNonLocalVarIndex = initAndGetVarIndexForNonLocalReturnValue();
Stack<TryCatchBlockNodeInfo> coveringTryCatchBlocks = new Stack<TryCatchBlockNodeInfo>();
InsnList instructions = inlineFun.instructions;
//As we do finally block code search after non-local return instruction
// we should be sure that all others non-local returns already processed in this finally block.
// So we do instruction processing in reverse order!
AbstractInsnNode curIns = instructions.getLast();
while (curIns != null) {
updateCoveringTryBlocks(coveringTryCatchBlocks, curIns);
//At this point only global return is possible, local one already substituted with: goto endLabel
if (!InlineCodegenUtil.isReturnOpcode(curIns.getOpcode()) || !InlineCodegenUtil.isMarkedReturn(curIns)) {
curIns = curIns.getPrevious();
continue;
}
AbstractInsnNode instrInsertFinallyBefore = curIns.getPrevious();
AbstractInsnNode nextPrev = instrInsertFinallyBefore.getPrevious();
Type nonLocalReturnType = InlineCodegenUtil.getReturnType(curIns.getOpcode());
//Generally there could be several tryCatch blocks (group) on one code interval (same start and end labels, but maybe different handlers) -
// all of them refer to one try/*catches*/finally or try/catches.
// Each group that corresponds to try/*catches*/finally contains tryCatch block with default handler.
// For each such group we should insert corresponding finally before non-local return.
// So we split all try blocks on current instructions to groups and process them independently
List<TryBlockCluster> clusters = InlinePackage.doClustering(coveringTryCatchBlocks);
ListIterator<TryBlockCluster> tryCatchBlockIterator = clusters.listIterator(clusters.size());
//Reverse visiting cause innermost tryCatchBlocks in the end
while (tryCatchBlockIterator.hasPrevious()) {
TryBlockCluster originalFinallyCluster = tryCatchBlockIterator.previous();
List<TryCatchBlockNodeInfo> clusterBlocks = originalFinallyCluster.getBlocks();
TryCatchBlockNodeInfo originalFinallyBlock = clusterBlocks.get(0);
FinallyBlockInfo finallyInfo = findFinallyBlockBody(originalFinallyBlock, inlineFunTryBlockInfo);
if (finallyInfo == null) continue;
instructions.resetLabels();
List<TryCatchBlockNodePosition> tryCatchBlockInlinedInFinally = findTryCatchBlocksInlinedInFinally(finallyInfo);
//Keep some information about label nodes, we need it to understand whether it's jump inside finally block or outside
// in first case we do call VISIT on instruction otherwise recreating jump instruction (see below)
Set<LabelNode> labelsInsideFinally = rememberOriginalLabelNodes(finallyInfo);
//Creating temp node for finally block copy with some additional instruction
MethodNode finallyBlockCopy = createEmptyMethodNode();
Label newFinallyStart = new Label();
Label newFinallyEnd = new Label();
if (nonLocalReturnType != Type.VOID_TYPE) {
finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ISTORE), nextTempNonLocalVarIndex);
}
finallyBlockCopy.visitLabel(newFinallyStart);
//Writing finally block body to temporary node
AbstractInsnNode currentIns = finallyInfo.startIns;
while (currentIns != finallyInfo.endInsExclusive) {
//This condition allows another model for non-local returns processing
if (false && InlineCodegenUtil.isReturnOpcode(currentIns.getOpcode()) && !InlineCodegenUtil.isMarkedReturn(currentIns)) {
//substitute all local returns in finally finallyInfo with non-local one lambdaFinallyBlocks try finallyInfo
//TODO same for jumps
Type localReturnType = InlineCodegenUtil.getReturnType(currentIns.getOpcode());
substituteReturnValueInFinally(nextTempNonLocalVarIndex, nonLocalReturnType, finallyBlockCopy,
localReturnType, true);
instrInsertFinallyBefore.accept(finallyBlockCopy);
curIns.accept(finallyBlockCopy);
}
else {
boolean isInsOrJumpInsideFinally =
!(currentIns instanceof JumpInsnNode) ||
labelsInsideFinally.contains(((JumpInsnNode) currentIns).label);
if (isInsOrJumpInsideFinally) {
currentIns.accept(finallyBlockCopy); //VISIT
}
else {
//keep original jump: add currentIns clone
finallyBlockCopy.instructions.add(new JumpInsnNode(currentIns.getOpcode(), ((JumpInsnNode) currentIns).label));
}
}
currentIns = currentIns.getNext();
}
finallyBlockCopy.visitLabel(newFinallyEnd);
if (nonLocalReturnType != Type.VOID_TYPE) {
finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ILOAD), nextTempNonLocalVarIndex);
nextTempNonLocalVarIndex += nonLocalReturnType.getSize(); //TODO: do more wise indexing
}
//Copying finally body before non-local return instruction
InlineCodegenUtil.insertNodeBefore(finallyBlockCopy, inlineFun, instrInsertFinallyBefore);
nextPrev = updateExceptionTable(coveringTryCatchBlocks, nextPrev, clusterBlocks, newFinallyStart, newFinallyEnd,
tryCatchBlockInlinedInFinally);
}
curIns = nextPrev;
}
inlineFun.tryCatchBlocks.clear();
for (TryCatchBlockNodeInfo info : inlineFunTryBlockInfo) {
inlineFun.tryCatchBlocks.add(info.getNode());
}
}
@NotNull
private static Set<LabelNode> rememberOriginalLabelNodes(@NotNull FinallyBlockInfo finallyInfo) {
Set<LabelNode> labelsInsideFinally = new HashSet<LabelNode>();
for (AbstractInsnNode currentIns = finallyInfo.startIns; currentIns != finallyInfo.endInsExclusive; currentIns = currentIns.getNext()) {
if (currentIns instanceof LabelNode) {
labelsInsideFinally.add((LabelNode) currentIns);
}
}
return labelsInsideFinally;
}
@Nullable
private AbstractInsnNode updateExceptionTable(
@NotNull Stack<TryCatchBlockNodeInfo> coveringTryBlocks,
@Nullable AbstractInsnNode nextPrev,
@NotNull List<TryCatchBlockNodeInfo> clusterBlocks,
@NotNull Label newFinallyStart,
@NotNull Label newFinallyEnd,
@NotNull List<TryCatchBlockNodePosition> tryCatchBlockPresentInFinally
) {
//copy tryCatchFinallies that totally in finally block
for (TryCatchBlockNodePosition position : tryCatchBlockPresentInFinally) {
//TODO assert INNER
TryCatchBlockNode tryCatchBlockNode = position.getNodeInfo().getNode();
TryCatchBlockNode additionalTryCatchBlock =
new TryCatchBlockNode((LabelNode) tryCatchBlockNode.start.getLabel().info,
(LabelNode) tryCatchBlockNode.end.getLabel().info,
(LabelNode) tryCatchBlockNode.handler.getLabel().info,
tryCatchBlockNode.type);
TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, true);
tryBlockStarts.put(additionalTryCatchBlock.start, newInfo);
tryBlockEnds.put(additionalTryCatchBlock.end, newInfo);
inlineFunTryBlockInfo.add(newInfo);
}
// Inserted finally shouldn't be handled by corresponding catches,
// so we should split original interval by inserted finally one
for (TryCatchBlockNodeInfo block : clusterBlocks) {
//update exception mapping
LabelNode oldStartNode = block.getNode().start;
tryBlockStarts.remove(oldStartNode, block);
block.getNode().start = (LabelNode) newFinallyEnd.info;
TryCatchBlockNode additionalTryCatchBlock =
new TryCatchBlockNode(oldStartNode, (LabelNode) newFinallyStart.info, block.getNode().handler, block.getNode().type);
TryCatchBlockNodeInfo newInfo = new TryCatchBlockNodeInfo(additionalTryCatchBlock, false);
tryBlockStarts.put(additionalTryCatchBlock.start, newInfo);
tryBlockEnds.put(additionalTryCatchBlock.end, newInfo);
inlineFunTryBlockInfo.add(newInfo);
//TODO add assert
nextPrev = additionalTryCatchBlock.end;
coveringTryBlocks.pop();
}
sortTryCatchBlocks();
return nextPrev;
}
//Keep information about try blocks that cover current instruction -
// pushing and popping it to stack entering and exiting tryCatchBlock start and end labels
private void updateCoveringTryBlocks(Stack<TryCatchBlockNodeInfo> coveringTryBlocks, AbstractInsnNode curIns) {
if (!(curIns instanceof LabelNode)) return;
for (TryCatchBlockNodeInfo startNode : tryBlockStarts.get((LabelNode) curIns)) {
if (!startNode.getOnlyCopyNotProcess()) {
TryCatchBlockNodeInfo pop = coveringTryBlocks.pop();
assert startNode == pop : "Wrong try-catch structure " + startNode + " " + pop;
}
}
//Reversing list order cause we should pop external block before internal one
// (originally internal blocks goes before external one, such invariant preserved via sortTryCatchBlocks method)
for (TryCatchBlockNodeInfo info : Lists.reverse(tryBlockEnds.get((LabelNode) curIns))) {
if (!info.getOnlyCopyNotProcess()) {
coveringTryBlocks.add(info);
}
}
}
private static boolean hasFinallyBlocks(List<TryCatchBlockNodeInfo> inlineFunTryBlockInfo) {
for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) {
if (!block.getOnlyCopyNotProcess() && block.getNode().type == null) {
return true;
}
}
return false;
}
private void mapLabelsToTryCatchBlocks() {
for (TryCatchBlockNodeInfo block : inlineFunTryBlockInfo) {
tryBlockStarts.put(block.getNode().start, block);
tryBlockEnds.put(block.getNode().end, block);
}
}
//As described above all tryCatch group that have finally block also should contains tryCatchBlockNode with default handler.
//So we assume that instructions between end of tryCatchBlock and start of next tryCatchBlock with same default handler is required finally body.
//There is at least two tryCatchBlockNodes in list cause there is always tryCatchBlockNode on first instruction of default handler:
// "ASTORE defaultHandlerExceptionIndex" (handles itself, as does java).
@Nullable
private FinallyBlockInfo findFinallyBlockBody(
@NotNull TryCatchBlockNodeInfo tryCatchBlock,
@NotNull List<TryCatchBlockNodeInfo> tryCatchBlocks
) {
List<TryCatchBlockNodeInfo> sameDefaultHandler = new ArrayList<TryCatchBlockNodeInfo>();
LabelNode defaultHandler = null;
boolean afterStartBlock = false;
for (TryCatchBlockNodeInfo block : tryCatchBlocks) {
if (tryCatchBlock == block) {
afterStartBlock = true;
}
if (afterStartBlock) {
if (block.getNode().type == null && (firstLabelInChain(tryCatchBlock.getNode().start) == firstLabelInChain(block.getNode().start) &&
firstLabelInChain(tryCatchBlock.getNode().end) == firstLabelInChain(block.getNode().end)
|| defaultHandler == firstLabelInChain(block.getNode().handler))) {
sameDefaultHandler.add(block); //first is tryCatchBlock if no catch clauses
if (defaultHandler == null) {
defaultHandler = firstLabelInChain(block.getNode().handler);
}
}
}
}
if (sameDefaultHandler.isEmpty()) {
//there is no finally block
//it always should be present in default handler
return null;
}
TryCatchBlockNodeInfo nextIntervalWithSameDefaultHandler = sameDefaultHandler.get(1);
AbstractInsnNode startFinallyChain = tryCatchBlock.getNode().end;
AbstractInsnNode endFinallyChainExclusive = skipLastGotoIfNeeded(nextIntervalWithSameDefaultHandler.getNode().handler,
nextIntervalWithSameDefaultHandler.getNode().start);
return new FinallyBlockInfo(startFinallyChain.getNext(), endFinallyChainExclusive);
}
@NotNull
private AbstractInsnNode skipLastGotoIfNeeded(
@NotNull LabelNode defaultHandlerStartLabel,
@NotNull AbstractInsnNode lastFinallyInsExclusive
) {
AbstractInsnNode prevLast = getPrevNoLineNumberOrLabel(lastFinallyInsExclusive, true);
assert prevLast != null : "Empty finally block: " + lastFinallyInsExclusive;
if (prevLast.getOpcode() == Opcodes.GOTO) {
//There we should understand whether goto is jump over catches or last break/continue command inside finally.
//If it's a jump over catches so next is true:
// 1. jump label should go after default catch handler start label
// AND
// 2. it shouldn't be present in default catch block, otherwise it break/continue
LabelNode targetJump = ((JumpInsnNode) prevLast).label;
InsnList instructions = inlineFun.instructions;
if (instructions.indexOf(defaultHandlerStartLabel) < instructions.indexOf(targetJump)) { //1 condition
AbstractInsnNode cur = defaultHandlerStartLabel;
while (cur != targetJump) {
if (cur.getOpcode() == Opcodes.GOTO) {
//noinspection ConstantConditions
if (((JumpInsnNode) cur).label == targetJump) { //fail of 2 condition
return lastFinallyInsExclusive;
}
}
cur = cur.getNext();
}
return prevLast;
}
}
return lastFinallyInsExclusive;
}
@NotNull
private List<TryCatchBlockNodePosition> findTryCatchBlocksInlinedInFinally(@NotNull FinallyBlockInfo finallyInfo) {
List<TryCatchBlockNodePosition> result = new ArrayList<TryCatchBlockNodePosition>();
Map<TryCatchBlockNodeInfo, TryCatchBlockNodePosition> processedBlocks = new HashMap<TryCatchBlockNodeInfo, TryCatchBlockNodePosition>();
for (AbstractInsnNode curInstr = finallyInfo.startIns; curInstr != finallyInfo.endInsExclusive; curInstr = curInstr.getNext()) {
if (!(curInstr instanceof LabelNode)) continue;
LabelNode curLabel = (LabelNode) curInstr;
List<TryCatchBlockNodeInfo> startedTryBlocks = tryBlockStarts.get(curLabel);
if (startedTryBlocks != null) {
for (TryCatchBlockNodeInfo block : startedTryBlocks) {
if (block.getOnlyCopyNotProcess()) {
assert !processedBlocks.containsKey(block) : "Try catch block already processed before start label!!! " + block;
TryCatchBlockNodePosition info = new TryCatchBlockNodePosition(block, TryCatchPosition.START);
processedBlocks.put(block, info);
result.add(info);
}
}
}
List<TryCatchBlockNodeInfo> endedTryBlocks = tryBlockEnds.get(curLabel);
if (endedTryBlocks == null) continue;
for (TryCatchBlockNodeInfo block : endedTryBlocks) {
if (block.getOnlyCopyNotProcess()) {
TryCatchBlockNodePosition info = processedBlocks.get(block);
if (info != null) {
assert info.getPosition() == TryCatchPosition.START;
info.setPosition(TryCatchPosition.INNER);
}
else {
info = new TryCatchBlockNodePosition(block, TryCatchPosition.END);
processedBlocks.put(block, info);
result.add(info);
}
}
}
}
return result;
}
private static void substituteReturnValueInFinally(
int nonLocalVarIndex,
@NotNull Type nonLocalReturnType,
@NotNull MethodNode finallyBlockCopy,
@NotNull Type localReturnType,
boolean doPop
) {
if (doPop && localReturnType != Type.VOID_TYPE) {
AsmUtil.pop(finallyBlockCopy, localReturnType);
}
if (nonLocalReturnType != Type.VOID_TYPE) {
finallyBlockCopy.visitVarInsn(nonLocalReturnType.getOpcode(Opcodes.ILOAD), nonLocalVarIndex);
}
}
@Nullable
private static AbstractInsnNode getPrevNoLineNumberOrLabel(@NotNull AbstractInsnNode node, boolean strict) {
AbstractInsnNode result = strict ? node.getPrevious() : node;
while (isLineNumberOrLabel(result)) {
result = result.getPrevious();
}
return result;
}
public void sortTryCatchBlocks() {
Comparator<TryCatchBlockNodeInfo> comp = new Comparator<TryCatchBlockNodeInfo>() {
@Override
public int compare(@NotNull TryCatchBlockNodeInfo t1, @NotNull TryCatchBlockNodeInfo t2) {
int result = inlineFun.instructions.indexOf(t1.getNode().handler) - inlineFun.instructions.indexOf(t2.getNode().handler);
if (result == 0) {
result = inlineFun.instructions.indexOf(t1.getNode().start) - inlineFun.instructions.indexOf(t2.getNode().start);
if (result == 0) {
assert false : "Error: support multicatch finallies!";
result = inlineFun.instructions.indexOf(t1.getNode().end) - inlineFun.instructions.indexOf(t2.getNode().end);
}
}
return result;
}
};
Collections.sort(inlineFunTryBlockInfo, comp);
}
}
@@ -16,6 +16,8 @@
package org.jetbrains.jet.codegen.inline;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
@@ -30,16 +32,18 @@ public class MaxCalcNode extends MethodVisitor {
private final MethodNode node;
public MaxCalcNode(MethodNode node) {
public MaxCalcNode(@NotNull MethodNode node) {
this(node.desc, node, (node.access & Opcodes.ACC_STATIC) != 0);
}
public MaxCalcNode(@NotNull String desc, boolean isStatic) {
this(desc, null, isStatic);
}
private MaxCalcNode(@NotNull String desc, @Nullable MethodNode node, boolean isStatic) {
super(InlineCodegenUtil.API, node);
this.node = node;
int paramsSize = (node.access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
Type[] types = Type.getArgumentTypes(node.desc);
for (Type type : types) {
paramsSize += type.getSize();
}
maxLocal = paramsSize;
maxLocal = (Type.getArgumentsAndReturnSizes(desc) >> 2) - (isStatic ? 1 : 0);
}
@Override
@@ -63,15 +67,24 @@ public class MaxCalcNode extends MethodVisitor {
public void visitMaxs(int maxStack, int maxLocals) {
//NB: it's hack for fast maxStack calculation cause it performed only in MethodWriter
//temporary solution: maxStack = instruction size (without labels and line numbers) * 2 (cause 1 instruction could put value of size 2)
int size = 0;
ListIterator<AbstractInsnNode> iterator = node.instructions.iterator();
while (iterator.hasNext()) {
AbstractInsnNode next = iterator.next();
int type = next.getType();
if (type != AbstractInsnNode.LINE && type != AbstractInsnNode.LABEL) {
size++;
if (node != null) {
int size = 0;
ListIterator<AbstractInsnNode> iterator = node.instructions.iterator();
while (iterator.hasNext()) {
AbstractInsnNode next = iterator.next();
int type = next.getType();
if (type != AbstractInsnNode.LINE && type != AbstractInsnNode.LABEL) {
size++;
}
}
super.visitMaxs(Math.max(size * 2, maxStack), Math.max(maxLocals, this.maxLocal));
}
super.visitMaxs(Math.max(size * 2, maxStack), Math.max(maxLocals, this.maxLocal));
else {
super.visitMaxs(maxStack, maxLocals);
}
}
public int getMaxLocal() {
return maxLocal;
}
}
@@ -34,9 +34,7 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.*;
import java.util.*;
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.getReturnType;
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.isAnonymousConstructorCall;
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.isInvokeOnLambda;
import static org.jetbrains.jet.codegen.inline.InlineCodegenUtil.*;
public class MethodInliner {
@@ -63,6 +61,8 @@ public class MethodInliner {
private final InlineResult result;
private int lambdasFinallyBlocks;
/*
*
* @param node
@@ -115,8 +115,12 @@ public class MethodInliner {
}
resultNode.visitLabel(end);
processReturns(resultNode, labelOwner, remapReturn, end);
if (inliningContext.isRoot()) {
InternalFinallyBlockInliner.processInlineFunFinallyBlocks(resultNode, lambdasFinallyBlocks);
}
processReturns(resultNode, labelOwner, remapReturn, end);
//flush transformed node to output
resultNode.accept(new InliningInstructionAdapter(adapter));
@@ -127,7 +131,7 @@ public class MethodInliner {
final Deque<InvokeCall> currentInvokes = new LinkedList<InvokeCall>(invokeCalls);
MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
final MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null);
final Iterator<ConstructorInvocation> iterator = constructorInvocations.iterator();
@@ -227,6 +231,12 @@ public class MethodInliner {
}
}
@Override
public void visitMaxs(int stack, int locals) {
lambdasFinallyBlocks = resultNode.tryCatchBlocks.size();
super.visitMaxs(stack, locals);
}
};
node.accept(lambdaInliner);
@@ -544,16 +554,17 @@ public class MethodInliner {
return new InlineException(errorPrefix + ": " + errorSuffix, originalException);
} else {
return new InlineException(errorPrefix + ": " + errorSuffix + "\ncause: " +
InlineCodegen.getNodeText(node), originalException);
getNodeText(node), originalException);
}
}
@NotNull
public static List<FinallyBlockInfo> processReturns(@NotNull MethodNode node, @NotNull LabelOwner labelOwner, boolean remapReturn, Label endLabel) {
//process local and global returns (local substituted with goto end-label global kept unchanged)
public static List<ExternalFinallyBlockInfo> processReturns(@NotNull MethodNode node, @NotNull LabelOwner labelOwner, boolean remapReturn, Label endLabel) {
if (!remapReturn) {
return Collections.emptyList();
}
List<FinallyBlockInfo> result = new ArrayList<FinallyBlockInfo>();
List<ExternalFinallyBlockInfo> result = new ArrayList<ExternalFinallyBlockInfo>();
InsnList instructions = node.instructions;
AbstractInsnNode insnNode = instructions.getFirst();
while (insnNode != null) {
@@ -584,23 +595,25 @@ public class MethodInliner {
}
//genetate finally block before nonLocalReturn flag/return/goto
result.add(new FinallyBlockInfo(isLocalReturn ? insnNode : insnNode.getPrevious(), getReturnType(insnNode.getOpcode())));
result.add(new ExternalFinallyBlockInfo(isLocalReturn ? insnNode : insnNode.getPrevious(), getReturnType(insnNode.getOpcode())
));
}
insnNode = insnNode.getNext();
}
return result;
}
public static class FinallyBlockInfo {
public static class ExternalFinallyBlockInfo {
final AbstractInsnNode beforeIns;
final Type returnType;
public FinallyBlockInfo(AbstractInsnNode beforeIns, Type returnType) {
public ExternalFinallyBlockInfo(AbstractInsnNode beforeIns, Type returnType) {
this.beforeIns = beforeIns;
this.returnType = returnType;
}
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.codegen.inline
import java.util.ArrayList
import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode
import org.jetbrains.org.objectweb.asm.tree.LabelNode
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.jet.codegen.inline.InlineCodegenUtil.*
enum class TryCatchPosition {
START
END
INNER
}
class TryCatchBlockNodeInfo(val node: TryCatchBlockNode, val onlyCopyNotProcess: Boolean)
class TryCatchBlockNodePosition(val nodeInfo: TryCatchBlockNodeInfo, var position: TryCatchPosition)
class TryBlockCluster(val blocks: MutableList<TryCatchBlockNodeInfo>)
fun doClustering(blocks: List<TryCatchBlockNodeInfo>) : List<TryBlockCluster> {
[data] class TryBlockInterval(val startLabel: LabelNode, val endLabel: LabelNode)
val clusters = linkedMapOf<TryBlockInterval, TryBlockCluster>()
blocks.forEach { block ->
val interval = TryBlockInterval(firstLabelInChain(block.node.start), firstLabelInChain(block.node.end))
val cluster = clusters.getOrPut(interval, {TryBlockCluster(arrayListOf())})
cluster.blocks.add(block)
}
return clusters.values().toList();
}
@@ -0,0 +1,102 @@
import test.*
import Kind.*
enum class Kind {
LOCAL
EXTERNAL
GLOBAL
}
class Holder {
var value: String = ""
}
val FINALLY_CHAIN = "in local finally, in declaration local finally, in external finally, in declaration external finally, in global finally"
class Internal(val value: String)
class External(val value: String)
class Global(val value: String)
fun test1(intKind: Kind, extKind: Kind, holder: Holder): Global {
holder.value = ""
try {
var externalResult = doCall (@ext {
(): External ->
try {
val internalResult = doCall (@int {
(): Internal ->
try {
if (intKind == Kind.GLOBAL) {
return@test1 Global("internal -> global")
}
else if (intKind == EXTERNAL) {
return@ext External("internal -> external")
}
return@int Internal("internal -> local")
}
finally {
holder.value += "in local finally"
}
}, {
holder.value += ", in declaration local finally"
})
if (extKind == GLOBAL || extKind == EXTERNAL) {
return Global("external -> global")
}
External(internalResult.value + ": external -> local");
}
finally {
holder.value += ", in external finally"
}
}, {
holder.value += ", in declaration external finally"
})
return Global(externalResult.value + ": exit")
}
finally {
holder.value += ", in global finally"
}
}
fun box(): String {
var holder = Holder()
var test1 = test1(LOCAL, LOCAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> local: external -> local: exit") return "test1: ${test1}, finally = ${holder.value}"
test1 = test1(EXTERNAL, LOCAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> external: exit") return "test2: ${test1}, finally = ${holder.value}"
test1 = test1(GLOBAL, LOCAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> global") return "test3: ${test1}, finally = ${holder.value}"
test1 = test1(LOCAL, EXTERNAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "external -> global") return "test4: ${test1}, finally = ${holder.value}"
test1 = test1(EXTERNAL, EXTERNAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> external: exit") return "test5: ${test1}, finally = ${holder.value}"
test1 = test1(GLOBAL, EXTERNAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> global") return "test6: ${test1}, finally = ${holder.value}"
test1 = test1(LOCAL, GLOBAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "external -> global") return "test7: ${test1}, finally = ${holder.value}"
test1 = test1(EXTERNAL, GLOBAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> external: exit") return "test8: ${test1}, finally = ${holder.value}"
test1 = test1(GLOBAL, GLOBAL, holder).value
if (holder.value != FINALLY_CHAIN || test1 != "internal -> global") return "test9: ${test1}, finally = ${holder.value}"
return "OK"
}
@@ -0,0 +1,9 @@
package test
public inline fun <R> doCall(block: ()-> R, finallyLambda: ()-> Unit) : R {
try {
return block()
} finally {
finallyLambda()
}
}
@@ -0,0 +1,129 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(h: Holder): Int {
val localResult = doCall2 (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
return 1
},
{
h.value += ", OK_EXCEPTION"
return 2
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
}, "FAILT")
return -1;
}
fun test1(h: Holder): Int {
val localResult = doCall2 (
{
h.value += "OK_NONLOCAL"
return 1
},
{
h.value += ", OK_EXCEPTION"
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
}, "FAIL")
return -1;
}
fun test2(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
2
},
{
h.value += ", OK_FINALLY"
3
})
return "" + localResult;
}
fun test3(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
return "OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
3
})
return "" + localResult;
}
fun test4(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
h.value += "fail"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
return "OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "" + localResult;
}
fun box(): String {
var h = Holder()
val test0 = test0(h)
if (test0 != 2 || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test0: ${test0}, holder: ${h.value}"
h = Holder()
val test1 = test1(h)
if (test1 != 1 || h.value != "OK_NONLOCAL, OK_FINALLY") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "OK_EXCEPTION" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test3: ${test3}, holder: ${h.value}"
h = Holder()
val test4 = test4(h)
if (test4 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test4: ${test4}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,23 @@
package test
public inline fun doCall(block: ()-> Int, exception: (e: Exception)-> Unit, finallyBlock: ()-> Int, res: Int = -111) : Int {
try {
return block()
} catch (e: Exception) {
exception(e)
} finally {
finallyBlock()
}
return res
}
public inline fun <R> doCall2(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R, res: R) : R {
try {
return block()
} catch (e: Exception) {
exception(e)
} finally {
finallyBlock()
}
return res
}
@@ -0,0 +1,129 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(h: Holder): Long {
val localResult = doCall2 (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
return 1.toLong()
},
{
h.value += ", OK_EXCEPTION"
return 2.toLong()
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
}, "FAIL")
return -1.toLong()
}
fun test1(h: Holder): Long {
val localResult = doCall2 (
{
h.value += "OK_NONLOCAL"
return 1.toLong()
},
{
h.value += ", OK_EXCEPTION"
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
}, "FAIL")
return -1.toLong()
}
fun test2(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
2.toLong()
},
{
h.value += ", OK_FINALLY"
3.toLong()
})
return "" + localResult;
}
fun test3(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
return "OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
3.toLong()
})
return "" + localResult;
}
fun test4(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
h.value += "fail"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
return "OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "" + localResult;
}
fun box(): String {
var h = Holder()
val test0 = test0(h)
if (test0 != 2.toLong() || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test0: ${test0}, holder: ${h.value}"
h = Holder()
val test1 = test1(h)
if (test1 != 1.toLong() || h.value != "OK_NONLOCAL, OK_FINALLY") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "OK_EXCEPTION" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test3: ${test3}, holder: ${h.value}"
h = Holder()
val test4 = test4(h)
if (test4 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test4: ${test4}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,23 @@
package test
public inline fun doCall(block: ()-> Long, exception: (e: Exception)-> Unit, finallyBlock: ()-> Long, res: Long = -1111.toLong()) : Long {
try {
block()
} catch (e: Exception) {
exception(e)
} finally {
finallyBlock()
}
return res
}
public inline fun <R> doCall2(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R, res: R) : R {
try {
return block()
} catch (e: Exception) {
exception(e)
} finally {
finallyBlock()
}
return res
}
@@ -0,0 +1,113 @@
import test.*
class Holder {
var value: String = ""
}
fun test1(h: Holder): String {
doCall (
{
h.value += "OK_LOCAL"
},
{
h.value += ", OK_FINALLY1"
},
{
h.value += ", OK_FINALLY2"
}
)
return "LOCAL";
}
fun test2(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
},
{
h.value += ", OK_FINALLY1"
},
{
h.value += ", OK_FINALLY2"
})
return "FAIL";
}
fun test3(h: Holder): String {
doCall (
{
h.value += "OK_LOCAL"
},
{
h.value += ", OK_FINALLY1"
return "OK_FINALLY1"
},
{
h.value += ", OK_FINALLY2"
})
return "FAIL";
}
fun test4(h: Holder): String {
doCall (
{
h.value += "OK_LOCAL"
},
{
h.value += ", OK_FINALLY1"
},
{
h.value += ", OK_FINALLY2"
return "OK_FINALLY2"
})
return "FAIL";
}
fun test5(h: Holder): String {
doCall (
{
h.value += "OK_LOCAL"
},
{
h.value += ", OK_FINALLY1"
return "OK_FINALLY1"
},
{
h.value += ", OK_FINALLY2"
return "OK_FINALLY2"
})
return "FAIL";
}
fun box(): String {
var h = Holder()
val test1 = test1(h)
if (test1 != "LOCAL" || h.value != "OK_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OK_FINALLY1, OK_FINALLY2") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "OK_FINALLY1" || h.value != "OK_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test3: ${test3}, holder: ${h.value}"
h = Holder()
val test4 = test4(h)
if (test4 != "OK_FINALLY2" || h.value != "OK_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test4: ${test4}, holder: ${h.value}"
h = Holder()
val test5 = test5(h)
if (test5 != "OK_FINALLY2" || h.value != "OK_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test5: ${test5}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,14 @@
package test
public inline fun doCall(block: ()-> Unit, finallyBlock1: ()-> Unit, finallyBlock2: ()-> Unit) {
try {
try {
block()
}
finally {
finallyBlock1()
}
} finally {
finallyBlock2()
}
}
@@ -0,0 +1,80 @@
import test.*
class Holder {
var value: String = ""
}
fun test1(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_LOCAL"
"OK_LOCAL"
}, {
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "FAIL";
}
fun test2(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
"OK_NONLOCAL"
}, {
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
return localResult;
}
fun test3(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
}, {
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "FAIL";
}
fun test4(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
}, {
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
return localResult;
}
fun box(): String {
var h = Holder()
val test1 = test1(h)
if (test1 != "OK_FINALLY" || h.value != "OK_LOCAL, OK_FINALLY") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test3: ${test3}, holder: ${h.value}"
h = Holder()
val test4 = test4(h)
if (test4 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test4: ${test4}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,9 @@
package test
public inline fun <R> doCall(block: ()-> R, finallyBlock: ()-> R) : R {
try {
block()
} finally {
return finallyBlock()
}
}
@@ -0,0 +1,59 @@
import test.*
class Holder {
var value: String = ""
}
fun test1(h: Holder): String {
val localResult = doCall ({
return "OK_NONLOCAL"
}, {
h.value = "OK_FINALLY"
})
return "FAIL";
}
fun test2(h: Holder): String {
val localResult = doCall (@lambda {
(): String ->
h.value += "OK_LOCAL"
return@lambda "OK_LOCAL"
}, {
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "FAIL";
}
fun test3(h: Holder): String {
val localResult = doCall ({
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
}, {
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "FAIL";
}
fun box(): String {
var h = Holder()
val test1 = test1(h)
if (test1 != "OK_NONLOCAL" || h.value != "OK_FINALLY") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "OK_FINALLY" || h.value != "OK_LOCAL, OK_FINALLY") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test3: ${test3}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,9 @@
package test
public inline fun <R> doCall(block: ()-> R, finallyBlock: ()-> Unit) : R {
try {
return block()
} finally {
finallyBlock()
}
}
@@ -0,0 +1,84 @@
import test.*
class Holder {
var value: String = ""
}
fun test1(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_LOCAL"
"OK_LOCAL"
}, {
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "FAIL";
}
fun test2(h: Holder): String {
val localResult = doCall (
@lambda {
(): String ->
h.value += "OK_NONLOCAL"
return@lambda "OK_NONLOCAL"
}, {
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
return localResult;
}
fun test3(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
}, {
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "FAIL";
}
fun test4(h: Holder): String {
val localResult = doCall (
{
():String ->
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
},
@l2 {
():String ->
h.value += ", OK_FINALLY"
return@l2 "OK_FINALLY"
})
return localResult;
}
fun box(): String {
var h = Holder()
val test1 = test1(h)
if (test1 != "OK_FINALLY" || h.value != "OK_LOCAL, OK_FINALLY") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test3: ${test3}, holder: ${h.value}"
h = Holder()
val test4 = test4(h)
if (test4 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test4: ${test4}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,9 @@
package test
public inline fun <R> doCall(block: ()-> R, finallyBlock: ()-> R) : R {
try {
return block()
} finally {
return finallyBlock()
}
}
@@ -0,0 +1,58 @@
import test.*
class Holder {
var value: String = ""
}
fun test1(h: Holder): String {
doCall ({
return "OK_NONLOCAL"
}, {
h.value = "OK_FINALLY"
})
return "FAIL";
}
fun test2(h: Holder): String {
doCall ({
h.value += "OK_LOCAL"
"OK_LOCAL"
}, {
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "FAIL";
}
fun test3(h: Holder): String {
doCall ({
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
}, {
h.value += ", OK_FINALLY"
return "OK_FINALLY"
})
return "FAIL";
}
fun box(): String {
var h = Holder()
val test1 = test1(h)
if (test1 != "OK_NONLOCAL" || h.value != "OK_FINALLY") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "OK_FINALLY" || h.value != "OK_LOCAL, OK_FINALLY") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test3: ${test3}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,9 @@
package test
public inline fun <R> doCall(block: ()-> R, finallyBlock: ()-> Unit) {
try {
block()
} finally {
finallyBlock()
}
}
@@ -0,0 +1,57 @@
import test.*
class Holder {
var value: String = ""
}
fun test1(h: Holder) {
val localResult = doCall (
{
h.value = "OK_NONLOCAL"
return
}, {
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
}
fun test2(h: Holder) {
val localResult = doCall (
{
h.value += "OK_LOCAL"
"OK_LOCAL"
}, {
h.value += ", OK_FINALLY"
return
})
}
fun test3(h: Holder) {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
return
}, {
h.value += ", OK_FINALLY"
return
})
}
fun box(): String {
var h = Holder()
test1(h)
if (h.value != "OK_NONLOCAL, OK_FINALLY") return "test1 holder: ${h.value}"
h = Holder()
test2(h)
if (h.value != "OK_LOCAL, OK_FINALLY") return "test2 holder: ${h.value}"
h = Holder()
test3(h)
if (h.value != "OK_NONLOCAL, OK_FINALLY") return "test3 holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,9 @@
package test
public inline fun <R> doCall(block: ()-> R, finallyBlock: ()-> Unit) : R {
try {
return block()
} finally {
finallyBlock()
}
}
@@ -0,0 +1,49 @@
import test.*
fun test1(): Int {
var s = 0
doCallAlwaysBreak {
s += it*it
s
}
return s;
}
fun test11(): Int {
return doCallAlwaysBreak {
return -100
}
}
fun test2(): Int {
return doCallAlwaysBreak2 {
return -100
}
}
fun test22(): Int {
var s = 0
doCallAlwaysBreak {
s += it*it
s
}
return s;
}
fun box(): String {
val test1 = test1()
if (test1 != 1) return "test1: ${test1}"
val test11 = test11()
if (test11 != 0) return "test11: ${test11}"
val test2 = test2()
if (test2 != 0) return "test2: ${test2}"
val test22 = test22()
if (test22 != 1) return "test22: ${test22}"
return "OK"
}
@@ -0,0 +1,41 @@
package test
public inline fun doCallAlwaysBreak(block: (i: Int)-> Int) : Int {
var res = 0;
for (i in 1..10) {
try {
block(i)
} finally {
break;
}
}
return res
}
public val z: Boolean = true
public inline fun doCallAlwaysBreak2(block: (i: Int)-> Int) : Int {
var res = 0;
for (i in 1..10) {
try {
res = block(i)
} finally {
if (z)
break
}
}
return res
}
//public inline fun doCallAlwaysBreak2(block: (i: Int)-> Int) : Int {
// var res = 0;
// for (i in 1..10) {
// try {
// res += block(i)
// } finally {
// if (z)
// break
// }
// }
// return res
//}
@@ -0,0 +1,48 @@
import test.*
fun test1(): Int {
var s = 0
doCallAlwaysBreak {
s += it*it
s
}
return s;
}
fun test11(): Int {
return doCallAlwaysBreak {
return -100
}
}
fun test2(): Int {
return doCallAlwaysBreak2 {
return -100
}
}
fun test22(): Int {
var s = 0
doCallAlwaysBreak {
s += it*it
s
}
return s;
}
fun box(): String {
val test1 = test1()
if (test1 != 385) return "test1: ${test1}"
val test11 = test11()
if (test11 != 0) return "test11: ${test11}"
val test2 = test2()
if (test2 != 0) return "test2: ${test2}"
val test22 = test22()
if (test22 != 385) return "test22: ${test22}"
return "OK"
}
@@ -0,0 +1,41 @@
package test
public inline fun doCallAlwaysBreak(block: (i: Int)-> Int) : Int {
var res = 0;
for (i in 1..10) {
try {
res = block(i)
} finally {
continue;
}
}
return res
}
public val z: Boolean = true
public inline fun doCallAlwaysBreak2(block: (i: Int)-> Int) : Int {
var res = 0;
for (i in 1..10) {
try {
res = block(i)
} finally {
if (z)
continue
}
}
return res
}
//public inline fun doCallAlwaysBreak2(block: (i: Int)-> Int) : Int {
// var res = 0;
// for (i in 1..10) {
// try {
// res += block(i)
// } finally {
// if (z)
// continue
// }
// }
// return res
//}
@@ -0,0 +1,40 @@
import test.*
class Holder {
var value: Int = 0
}
fun test1(): Int {
var s = 0
doCall (
{
s += it * it
s
},
{
s += it
}
)
return s;
}
fun test11(h: Holder): Int {
return doCall (
{
return -100
}, {
h.value += it
})
}
fun box(): String {
val test1 = test1()
if (test1 != 935) return "test1: ${test1}"
val h = Holder()
val test11 = test11(h)
if (test11 != -100 && h.value != 55) return "test11: ${test11} holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,15 @@
package test
public inline fun doCall(block: (i: Int)-> Int, fblock: (i: Int)-> Unit) : Int {
var res = 0;
for (i in 1..10) {
try {
res = block(i)
} finally {
for (i in 1..10) {
fblock(i)
}
}
}
return res
}
@@ -0,0 +1,120 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
return "OK_NON_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
return "OK_EXCEPTION2"
},
{
try {
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
"OK_FINALLY"
} finally {
h.value += ", OK_FINALLY_INNER"
}
})
return localResult;
}
catch (e: RuntimeException) {
if (e.getMessage() != "FINALLY") {
return "FAIL in exception: " + e.getMessage()
}
else {
return "CATCHED_EXCEPTION"
}
}
return "FAIL";
}
fun test01(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
throw Exception1("1")
return "OK_NON_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
return "OK_EXCEPTION2"
},
{
try {
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
} catch(e: RuntimeException) {
h.value += ", OK_CATCHED"
} finally {
h.value += ", OK_FINALLY_INNER"
}
"OK_FINALLY"
})
return localResult;
}
fun test02(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
throw Exception2("1")
return "OK_NON_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
return "OK_EXCEPTION2"
},
{
try {
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
} catch(e: RuntimeException) {
h.value += ", OK_CATCHED"
} finally {
h.value += ", OK_FINALLY_INNER"
}
"OK_FINALLY"
}, "OK")
return localResult;
}
fun box(): String {
var h = Holder()
val test0 = test0(h)
if (test0 != "CATCHED_EXCEPTION" || h.value != "OK_NON_LOCAL, OK_FINALLY, OK_FINALLY_INNER") return "test0: ${test0}, holder: ${h.value}"
h = Holder()
val test01 = test01(h)
if (test01 != "OK_EXCEPTION1" || h.value != "OK_NON_LOCAL, OK_EXCEPTION1, OK_FINALLY, OK_CATCHED, OK_FINALLY_INNER") return "test01: ${test01}, holder: ${h.value}"
h = Holder()
val test02 = test02(h)
if (test02 != "OK_EXCEPTION2" || h.value != "OK_NON_LOCAL, OK_EXCEPTION2, OK_FINALLY, OK_CATCHED, OK_FINALLY_INNER") return "test02: ${test02}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,29 @@
package test
public class Exception1(message: String) : java.lang.RuntimeException(message)
public class Exception2(message: String) : java.lang.RuntimeException(message)
public inline fun doCall(block: ()-> String, exception: (e: Exception)-> Unit, exception2: (e: Exception)-> Unit, finallyBlock: ()-> String, res: String = "Fail") : String {
try {
block()
} catch (e: Exception1) {
exception(e)
} catch (e: Exception2) {
exception2(e)
} finally {
finallyBlock()
}
return res
}
public inline fun <R> doCall2(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R) : R {
try {
return block()
} catch (e: Exception) {
exception(e)
} finally {
finallyBlock()
}
throw java.lang.RuntimeException("fail")
}
@@ -0,0 +1,115 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(h: Holder, throwEx1: Boolean, throwEx2: Boolean, throwEx3: Boolean = false, throwEx4: Boolean = false): String {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
if (throwEx1) {
throw Exception1("1")
}
if (throwEx2) {
throw Exception2("1")
}
return "OK_NON_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
if (throwEx3) {
throw Exception1("3_1")
}
if (throwEx4) {
throw Exception2("4_1")
}
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
if (throwEx3) {
throw Exception1("3_2")
}
if (throwEx4) {
throw Exception2("4_2")
}
return "OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY1"
try {
try {
throw Exception1("fail")
}
catch (e: RuntimeException) {
h.value += ", CATCHED1"
}
finally {
h.value += ", ADDITIONAL"
}
} finally {
h.value += " FINALLY1"
}
"OK_FINALLY1"
},
{
h.value += ", OK_EXCEPTION3"
return "OK_EXCEPTION3"
},
{
h.value += ", OK_EXCEPTION4"
return "OK_EXCEPTION4"
},
{
h.value += ", OK_FINALLY2"
try {
try {
throw Exception1("fail2")
} catch (e: RuntimeException) {
h.value += ", CATCHED2"
} finally {
h.value += ", ADDITIONAL"
}
} finally {
h.value += " FINALLY2"
}
"OK_FINALLY2"
})
return localResult;
return "FAIL";
}
fun box(): String {
var h = Holder()
var test0 = test0(h, false, false)
if (test0 != "OK_NON_LOCAL" || h.value != "OK_NON_LOCAL, OK_FINALLY1, CATCHED1, ADDITIONAL FINALLY1, OK_FINALLY2, CATCHED2, ADDITIONAL FINALLY2") return "test0_1: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, false)
if (test0 != "OK_EXCEPTION1" || h.value != "OK_NON_LOCAL, OK_EXCEPTION1, OK_FINALLY1, CATCHED1, ADDITIONAL FINALLY1, OK_FINALLY2, CATCHED2, ADDITIONAL FINALLY2") return "test0_2: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, true)
if (test0 != "OK_EXCEPTION2" || h.value != "OK_NON_LOCAL, OK_EXCEPTION2, OK_FINALLY1, CATCHED1, ADDITIONAL FINALLY1, OK_FINALLY2, CATCHED2, ADDITIONAL FINALLY2") return "test0_3: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, false, true, false)
if (test0 != "OK_EXCEPTION3" || h.value != "OK_NON_LOCAL, OK_EXCEPTION1, OK_FINALLY1, CATCHED1, ADDITIONAL FINALLY1, OK_EXCEPTION3, OK_FINALLY2, CATCHED2, ADDITIONAL FINALLY2") return "test0_4: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, false, false, true)
if (test0 != "OK_EXCEPTION4" || h.value != "OK_NON_LOCAL, OK_EXCEPTION1, OK_FINALLY1, CATCHED1, ADDITIONAL FINALLY1, OK_EXCEPTION4, OK_FINALLY2, CATCHED2, ADDITIONAL FINALLY2") return "test0_5: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, true, true, false)
if (test0 != "OK_EXCEPTION3" || h.value != "OK_NON_LOCAL, OK_EXCEPTION2, OK_FINALLY1, CATCHED1, ADDITIONAL FINALLY1, OK_EXCEPTION3, OK_FINALLY2, CATCHED2, ADDITIONAL FINALLY2") return "test0_6: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, true, false, true)
if (test0 != "OK_EXCEPTION4" || h.value != "OK_NON_LOCAL, OK_EXCEPTION2, OK_FINALLY1, CATCHED1, ADDITIONAL FINALLY1, OK_EXCEPTION4, OK_FINALLY2, CATCHED2, ADDITIONAL FINALLY2") return "test0_7: ${test0}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,32 @@
package test
public class Exception1(message: String) : java.lang.RuntimeException(message)
public class Exception2(message: String) : java.lang.RuntimeException(message)
public inline fun doCall(block: ()-> String, exception1: (e: Exception)-> Unit, exception2: (e: Exception)-> Unit, finallyBlock: ()-> String,
exception3: (e: Exception)-> Unit, exception4: (e: Exception)-> Unit, finallyBlock2: ()-> String, res: String = "Fail") : String {
try {
try {
block()
}
catch (e: Exception1) {
exception1(e)
}
catch (e: Exception2) {
exception2(e)
}
finally {
finallyBlock()
}
} catch (e: Exception1) {
exception3(e)
}
catch (e: Exception2) {
exception4(e)
}
finally {
finallyBlock2()
}
return res
}
@@ -0,0 +1,36 @@
import test.*
class Holder {
var value: String = ""
}
fun test01(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
throw Exception1("1")
"OK_NON_LOCAL_RES"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION1"
},
{
try {
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
} catch(e: RuntimeException) {
h.value += ", OK_CATCHED"
}
"OK_FINALLY_RES"
}, "FAIL")
return localResult;
}
fun box(): String {
var h = Holder()
val test01 = test01(h)
if (test01 != "OK_EXCEPTION1" || h.value != "OK_NON_LOCAL, OK_EXCEPTION1, OK_FINALLY, OK_CATCHED") return "test01: ${test01}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,14 @@
package test
public class Exception1(message: String) : java.lang.RuntimeException(message)
public inline fun doCall(block: ()-> String, exception: (e: Exception)-> Unit, finallyBlock: ()-> String, res: String = "Fail") : String {
try {
block()
} catch (e: Exception1) {
exception(e)
} finally {
finallyBlock()
}
return res
}
@@ -0,0 +1,91 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(h: Holder, throwEx1: Boolean, throwEx2: Boolean, throwEx3: Boolean = false, throwEx4: Boolean = false): String {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
if (throwEx1) {
throw Exception1("1")
}
if (throwEx2) {
throw Exception2("1")
}
return "OK_NON_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
if (throwEx3) {
throw Exception1("3_1")
}
if (throwEx4) {
throw Exception2("4_1")
}
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
if (throwEx3) {
throw Exception1("3_2")
}
if (throwEx4) {
throw Exception2("4_2")
}
return "OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY1"
"OK_FINALLY1"
},
{
h.value += ", OK_EXCEPTION3"
return "OK_EXCEPTION3"
},
{
h.value += ", OK_EXCEPTION4"
return "OK_EXCEPTION4"
},
{
h.value += ", OK_FINALLY2"
"OK_FINALLY2"
})
return localResult;
return "FAIL";
}
fun box(): String {
var h = Holder()
var test0 = test0(h, false, false)
if (test0 != "OK_NON_LOCAL" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_1: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, false)
if (test0 != "OK_EXCEPTION1" || h.value != "OK_NON_LOCAL, OK_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_2: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, true)
if (test0 != "OK_EXCEPTION2" || h.value != "OK_NON_LOCAL, OK_EXCEPTION2, OK_FINALLY1, OK_FINALLY2") return "test0_3: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, false, true, false)
if (test0 != "OK_EXCEPTION3" || h.value != "OK_NON_LOCAL, OK_EXCEPTION1, OK_FINALLY1, OK_EXCEPTION3, OK_FINALLY2") return "test0_4: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, false, false, true)
if (test0 != "OK_EXCEPTION4" || h.value != "OK_NON_LOCAL, OK_EXCEPTION1, OK_FINALLY1, OK_EXCEPTION4, OK_FINALLY2") return "test0_5: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, true, true, false)
if (test0 != "OK_EXCEPTION3" || h.value != "OK_NON_LOCAL, OK_EXCEPTION2, OK_FINALLY1, OK_EXCEPTION3, OK_FINALLY2") return "test0_6: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, true, false, true)
if (test0 != "OK_EXCEPTION4" || h.value != "OK_NON_LOCAL, OK_EXCEPTION2, OK_FINALLY1, OK_EXCEPTION4, OK_FINALLY2") return "test0_7: ${test0}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,32 @@
package test
public class Exception1(message: String) : java.lang.RuntimeException(message)
public class Exception2(message: String) : java.lang.RuntimeException(message)
public inline fun doCall(block: ()-> String, exception1: (e: Exception)-> Unit, exception2: (e: Exception)-> Unit, finallyBlock: ()-> String,
exception3: (e: Exception)-> Unit, exception4: (e: Exception)-> Unit, finallyBlock2: ()-> String, res: String = "Fail") : String {
try {
try {
block()
}
catch (e: Exception1) {
exception1(e)
}
catch (e: Exception2) {
exception2(e)
}
finally {
finallyBlock()
}
} catch (e: Exception1) {
exception3(e)
}
catch (e: Exception2) {
exception4(e)
}
finally {
finallyBlock2()
}
return res
}
@@ -0,0 +1,130 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(
h: Holder,
throwExceptionInTry: Boolean,
throwInternalEx2: Boolean = false,
throwInternalFinEx1: Boolean = false,
throwInternalFinEx2: Boolean = false,
throwExternalFinEx1: Boolean = false,
throwExternalFinEx2: Boolean = false,
res: String = "Fail"
): String {
try {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
if (throwExceptionInTry) {
throw Exception1("1")
}
return "OK_NON_LOCAL"
},
{
h.value += ", OK_INTERNAL_EXCEPTION1"
if (throwInternalEx2) {
throw Exception2("2_1")
}
return "OK_INTERNAL_EXCEPTION1"
},
{
h.value += ", OK_FINALLY1"
if (throwInternalFinEx1) {
throw Exception1("EXCEPTION_IN_INTERNAL_FINALLY")
}
if (throwInternalFinEx2) {
throw Exception2("EXCEPTION222_IN_INTERNAL_FINALLY")
}
"OK_FINALLY1"
},
{
h.value += ", OK_EXTERNAL_EXCEPTION2"
return "OK_EXTERNAL_EXCEPTION2"
},
{
h.value += ", OK_FINALLY2"
if (throwExternalFinEx1) {
throw Exception1("EXCEPTION_IN_EXTERNAL_FINALLY")
}
if (throwExternalFinEx2) {
throw Exception2("EXCEPTION222_IN_EXTERNAL_FINALLY")
}
"OK_FINALLY2"
}, res)
return localResult;
} catch(e: Exception1) {
return e.getMessage()!!
} catch(e: Exception2) {
return e.getMessage()!!
}
}
fun box(): String {
var h = Holder()
var test0 = test0(h, false, throwExternalFinEx1 = false, res = "OK")
if (test0 != "OK_INNER_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_1: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, throwExternalFinEx1 = true, res = "OK")
if (test0 != "EXCEPTION_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_2: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, throwExternalFinEx2 = true, res = "OK")
if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_4: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, throwExternalFinEx1 = true, res = "OK")
if (test0 != "EXCEPTION_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_3: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, throwInternalEx2 = true, throwExternalFinEx1 = true, res = "OK")
if (test0 != "EXCEPTION_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_5: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, throwInternalEx2 = true, throwExternalFinEx2 = true, res = "OK")
if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_6: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, throwInternalFinEx1 = true)
if (test0 != "EXCEPTION_IN_INTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_7: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, throwInternalFinEx1 = true, throwExternalFinEx2 = true)
if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_71: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, throwInternalFinEx2 = true)
if (test0 != "OK_EXTERNAL_EXCEPTION2" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_EXTERNAL_EXCEPTION2, OK_FINALLY2") return "test0_8: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, false, throwInternalFinEx2 = true, throwExternalFinEx2 = true)
if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_EXTERNAL_EXCEPTION2, OK_FINALLY2") return "test0_81: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, throwInternalFinEx1 = true)
if (test0 != "EXCEPTION_IN_INTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_9: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, throwInternalFinEx1 = true, throwExternalFinEx2 = true)
if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_10: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, throwInternalFinEx2 = true)
if (test0 != "OK_EXTERNAL_EXCEPTION2" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_EXTERNAL_EXCEPTION2, OK_FINALLY2") return "test0_11: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, true, throwInternalFinEx2 = true, throwExternalFinEx2 = true)
if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_EXTERNAL_EXCEPTION2, OK_FINALLY2") return "test0_12: ${test0}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,30 @@
package test
public class Exception1(message: String) : java.lang.RuntimeException(message)
public class Exception2(message: String) : java.lang.RuntimeException(message)
public inline fun doCall(block: ()-> String, exception1: (e: Exception)-> Unit, finallyBlock: ()-> String,
exception3: (e: Exception)-> Unit, finallyBlock2: ()-> String, res: String = "Fail") : String {
try {
try {
block()
}
catch (e: Exception1) {
exception1(e)
}
finally {
if (true) {
finallyBlock()
/*External finally would be injected here*/
return res + "_INNER_FINALLY"
}
}
} catch (e: Exception2) {
exception3(e)
}
finally {
finallyBlock2()
}
return res
}
@@ -0,0 +1,102 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(
h: Holder,
throwExternalFinEx1: Boolean = false,
res: String = "Fail"
): String {
try {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
return "OK_NON_LOCAL"
},
{
h.value += ", OK_FINALLY1"
"OK_FINALLY1"
},
{
h.value += ", OK_FINALLY2"
if (throwExternalFinEx1) {
throw Exception1("EXCEPTION_IN_EXTERNAL_FINALLY")
}
"OK_FINALLY2"
}, res)
return localResult;
} catch(e: Exception1) {
return e.getMessage()!!
} catch(e: Exception2) {
return e.getMessage()!!
}
}
fun box(): String {
var h = Holder()
var test0 = test0(h, res = "OK")
if (test0 != "OK_INNER_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_1: ${test0}, holder: ${h.value}"
h = Holder()
test0 = test0(h, throwExternalFinEx1 = true, res = "OK")
if (test0 != "EXCEPTION_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_2: ${test0}, holder: ${h.value}"
// h = Holder()
// test0 = test0(h, throwExternalFinEx2 = true, res = "OK")
// if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_4: ${test0}, holder: ${h.value}"
// h = Holder()
// test0 = test0(h, true, throwExternalFinEx1 = true, res = "OK")
// if (test0 != "EXCEPTION_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_3: ${test0}, holder: ${h.value}"
//
// h = Holder()
// test0 = test0(h, true, throwInternalEx2 = true, throwExternalFinEx1 = true, res = "OK")
// if (test0 != "EXCEPTION_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_5: ${test0}, holder: ${h.value}"
//
// h = Holder()
// test0 = test0(h, true, throwInternalEx2 = true, throwExternalFinEx2 = true, res = "OK")
// if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_6: ${test0}, holder: ${h.value}"
//
//
//
// h = Holder()
// test0 = test0(h, false, throwInternalFinEx1 = true, res = "FAIL")
// if (test0 != "EXCEPTION_IN_INTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_7: ${test0}, holder: ${h.value}"
//
// h = Holder()
// test0 = test0(h, false, throwInternalFinEx1 = true, throwExternalFinEx2 = true, res = "FAIL")
// if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_FINALLY2") return "test0_71: ${test0}, holder: ${h.value}"
//
// h = Holder()
// test0 = test0(h, false, throwInternalFinEx2 = true, res = "FAIL")
// if (test0 != "OK_EXTERNAL_EXCEPTION2" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_EXTERNAL_EXCEPTION2, OK_FINALLY2") return "test0_8: ${test0}, holder: ${h.value}"
//
// h = Holder()
// test0 = test0(h, false, throwInternalFinEx2 = true, throwExternalFinEx2 = true, res = "FAIL")
// if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_FINALLY1, OK_EXTERNAL_EXCEPTION2, OK_FINALLY2") return "test0_81: ${test0}, holder: ${h.value}"
//
//
//
// h = Holder()
// test0 = test0(h, true, throwInternalFinEx1 = true, res = "FAIL")
// if (test0 != "EXCEPTION_IN_INTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_9: ${test0}, holder: ${h.value}"
//
// h = Holder()
// test0 = test0(h, true, throwInternalFinEx1 = true, throwExternalFinEx2 = true, res = "FAIL")
// if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_FINALLY2") return "test0_10: ${test0}, holder: ${h.value}"
//
// h = Holder()
// test0 = test0(h, true, throwInternalFinEx2 = true, res = "FAIL")
// if (test0 != "OK_EXTERNAL_EXCEPTION2" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_EXTERNAL_EXCEPTION2, OK_FINALLY2") return "test0_11: ${test0}, holder: ${h.value}"
//
// h = Holder()
// test0 = test0(h, true, throwInternalFinEx2 = true, throwExternalFinEx2 = true, res = "FAIL")
// if (test0 != "EXCEPTION222_IN_EXTERNAL_FINALLY" || h.value != "OK_NON_LOCAL, OK_INTERNAL_EXCEPTION1, OK_FINALLY1, OK_EXTERNAL_EXCEPTION2, OK_FINALLY2") return "test0_12: ${test0}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,24 @@
package test
public class Exception1(message: String) : java.lang.RuntimeException(message)
public class Exception2(message: String) : java.lang.RuntimeException(message)
public inline fun doCall(block: ()-> String, finallyBlock: ()-> String,
finallyBlock2: ()-> String, res: String = "Fail") : String {
try {
try {
block()
}
finally {
if (true) {
finallyBlock()
/*External finally would be injected here*/
return res + "_INNER_FINALLY"
}
}
} finally {
finallyBlock2()
}
return res
}
@@ -0,0 +1,105 @@
import test.*
class Holder {
var value: String = ""
}
fun test2(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
"OK_EXCEPTION"
})
return localResult;
}
fun test3(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
return "OK_EXCEPTION"
})
return localResult;
}
fun test4(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
h.value += "fail"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
return "OK_EXCEPTION"
})
return localResult;
}
fun test5(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
h.value += "fail"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
if (true) {
throw java.lang.RuntimeException("EXCEPTION")
}
h.value += "fail"
return "OK_EXCEPTION"
})
return localResult;
} catch (e: RuntimeException) {
if (e.getMessage() != "EXCEPTION") {
return "FAIL in exception: " + e.getMessage()
} else {
return "CATCHED_EXCEPTION"
}
}
}
fun box(): String {
var h = Holder()
val test2 = test2(h)
if (test2 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "OK_EXCEPTION" || h.value != "OK_NONLOCAL, OK_EXCEPTION") return "test3: ${test3}, holder: ${h.value}"
h = Holder()
val test4 = test4(h)
if (test4 != "OK_EXCEPTION" || h.value != "OK_NONLOCAL, OK_EXCEPTION") return "test4: ${test4}, holder: ${h.value}"
h = Holder()
val test5 = test5(h)
if (test5 != "CATCHED_EXCEPTION" || h.value != "OK_NONLOCAL, OK_EXCEPTION") return "test5: ${test5}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,10 @@
package test
public inline fun doCall(block: ()-> String, exception: (e: Exception)-> Unit) : String {
try {
return block()
} catch (e: Exception) {
exception(e)
}
return "Fail in doCall"
}
@@ -0,0 +1,278 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
return "OK_NON_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
return "OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
"OK_FINALLY"
})
return localResult;
}
catch (e: RuntimeException) {
if (e.getMessage() != "FINALLY") {
return "FAIL in exception: " + e.getMessage()
}
else {
return "CATCHED_EXCEPTION"
}
}
return "FAIL";
}
fun test01(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
throw Exception1("1")
return "OK_NON_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
return "OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
return localResult;
}
fun test02(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
throw Exception2("1")
return "OK_NON_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
return "OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
return localResult;
}
fun test1(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_LOCAL"
throw Exception1("FAIL")
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
return "OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
"OK_FINALLY"
}, "Fail")
}
catch (e: RuntimeException) {
if (e.getMessage() != "FINALLY") {
return "FAIL in exception: " + e.getMessage()
}
else {
return "CATCHED_EXCEPTION"
}
}
return "FAIL";
}
fun test2(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_LOCAL"
throw Exception1("1")
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
throw Exception2("2")
"OK_EXCEPTION"
},
{
h.value += ", OK_EXCEPTION2"
"OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
return localResult;
}
catch (e: Exception2) {
return "CATCHED_EXCEPTION"
}
return "Fail";
}
fun test3(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_LOCAL"
throw Exception2("FAIL")
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION1"
},
{
h.value += ", OK_EXCEPTION2"
return "OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
"OK_FINALLY"
}, "Fail")
}
catch (e: RuntimeException) {
if (e.getMessage() != "FINALLY") {
return "FAIL in exception: " + e.getMessage()
}
else {
return "CATCHED_EXCEPTION"
}
}
return "FAIL";
}
fun test4(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_LOCAL"
throw Exception2("1")
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION1"
return "OK_EXCEPTION"
},
{
h.value += ", OK_EXCEPTION2"
throw Exception1("1")
"OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
return localResult;
}
catch (e: Exception1) {
return "CATCHED_EXCEPTION"
}
return "Fail";
}
fun test5(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_LOCAL"
throw Exception2("FAIL")
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION"
throw java.lang.RuntimeException("FAIL_EX")
"OK_EXCEPTION"
},
{
h.value += ", OK_EXCEPTION2"
return "OK_EXCEPTION2"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
return localResult;
}
fun box(): String {
var h = Holder()
val test0 = test0(h)
if (test0 != "CATCHED_EXCEPTION" || h.value != "OK_NON_LOCAL, OK_FINALLY") return "test0: ${test0}, holder: ${h.value}"
h = Holder()
val test01 = test01(h)
if (test01 != "OK_EXCEPTION1" || h.value != "OK_NON_LOCAL, OK_EXCEPTION1, OK_FINALLY") return "test01: ${test01}, holder: ${h.value}"
h = Holder()
val test02 = test02(h)
if (test02 != "OK_EXCEPTION2" || h.value != "OK_NON_LOCAL, OK_EXCEPTION2, OK_FINALLY") return "test02: ${test02}, holder: ${h.value}"
h = Holder()
val test1 = test1(h)
if (test1 != "CATCHED_EXCEPTION" || h.value != "OK_LOCAL, OK_EXCEPTION1, OK_FINALLY") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "CATCHED_EXCEPTION" || h.value != "OK_LOCAL, OK_EXCEPTION1, OK_FINALLY") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "CATCHED_EXCEPTION" || h.value != "OK_LOCAL, OK_EXCEPTION2, OK_FINALLY") return "test3: ${test3}, holder: ${h.value}"
h = Holder()
val test4 = test4(h)
if (test4 != "CATCHED_EXCEPTION" || h.value != "OK_LOCAL, OK_EXCEPTION2, OK_FINALLY") return "test4: ${test4}, holder: ${h.value}"
h = Holder()
val test5 = test5(h)
if (test5 != "OK_EXCEPTION2" || h.value != "OK_LOCAL, OK_EXCEPTION2, OK_FINALLY") return "test5: ${test5}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,29 @@
package test
public class Exception1(message: String) : java.lang.RuntimeException(message)
public class Exception2(message: String) : java.lang.RuntimeException(message)
public inline fun doCall(block: ()-> String, exception: (e: Exception)-> Unit, exception2: (e: Exception)-> Unit, finallyBlock: ()-> String, res: String = "Fail") : String {
try {
block()
} catch (e: Exception1) {
exception(e)
} catch (e: Exception2) {
exception2(e)
} finally {
finallyBlock()
}
return res
}
public inline fun <R> doCall2(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R) : R {
try {
return block()
} catch (e: Exception) {
exception(e)
} finally {
finallyBlock()
}
throw java.lang.RuntimeException("fail")
}
@@ -0,0 +1,196 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_LOCAL"
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION"
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
}, "Fail")
return localResult;
}
fun test1(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_LOCAL"
throw java.lang.RuntimeException()
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION"
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
}, "OK")
return localResult;
}
fun test2(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
}, "FAIL")
return localResult;
}
fun test3(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
return "OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
}, "FAIL")
return localResult;
}
fun test4(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
h.value += "fail"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
return "OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
return "OK_FINALLY"
}, "FAIL")
return localResult;
}
fun test5(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
h.value += "fail"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
if (true) {
throw java.lang.RuntimeException()
}
h.value += "fail"
return "OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
return "OK_FINALLY"
}, "FAIL")
return localResult;
}
fun test6(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_NONLOCAL"
if (true) {
throw java.lang.RuntimeException()
}
h.value += "fail"
return "OK_NONLOCAL"
},
{
h.value += ", OK_EXCEPTION"
if (true) {
throw java.lang.RuntimeException()
}
h.value += "fail"
return "OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
},
"FAIL1")
} catch (e: Exception) {
return "OK"
}
return "FAIL2";
}
fun box(): String {
var h = Holder()
val test0 = test0(h)
if (test0 != "OK_LOCAL" || h.value != "OK_LOCAL, OK_FINALLY") return "test0: ${test0}, holder: ${h.value}"
h = Holder()
val test1 = test1(h)
if (test1 != "OK" || h.value != "OK_LOCAL, OK_EXCEPTION, OK_FINALLY") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "OK_NONLOCAL" || h.value != "OK_NONLOCAL, OK_FINALLY") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "OK_EXCEPTION" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test3: ${test3}, holder: ${h.value}"
h = Holder()
val test4 = test4(h)
if (test4 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test4: ${test4}, holder: ${h.value}"
h = Holder()
val test5 = test5(h)
if (test5 != "OK_FINALLY" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test5: ${test5}, holder: ${h.value}"
h = Holder()
val test6 = test6(h)
if (test6 != "OK" || h.value != "OK_NONLOCAL, OK_EXCEPTION, OK_FINALLY") return "test6: ${test6}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,12 @@
package test
public inline fun <R> doCall(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R, res: R) : R {
try {
return block()
} catch (e: Exception) {
exception(e)
} finally {
finallyBlock()
}
return res
}
@@ -0,0 +1,168 @@
import test.*
class Holder {
var value: String = ""
}
fun test0(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_NON_LOCAL"
return "OK_NON_LOCAL"
},
{
h.value += ", OK_EXCEPTION"
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
"OK_FINALLY"
})
return localResult;
} catch (e: RuntimeException) {
if (e.getMessage() != "FINALLY") {
return "FAIL in exception: " + e.getMessage()
} else {
return "CATCHED_EXCEPTION"
}
}
return "FAIL";
}
fun test1(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_LOCAL"
throw java.lang.RuntimeException("FAIL")
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION"
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
"OK_FINALLY"
})
} catch (e: RuntimeException) {
if (e.getMessage() != "FINALLY") {
return "FAIL in exception: " + e.getMessage()
} else {
return "CATCHED_EXCEPTION"
}
}
return "FAIL";
}
fun test2(h: Holder): String {
val localResult = doCall (
{
h.value += "OK_LOCAL"
throw java.lang.RuntimeException()
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION"
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
return localResult;
}
fun test3(h: Holder): String {
try {
val localResult = doCall (
{
h.value += "OK_LOCAL"
throw java.lang.RuntimeException("FAIL")
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION"
throw java.lang.RuntimeException("FAIL_EX")
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
throw java.lang.RuntimeException("FINALLY")
"OK_FINALLY"
})
} catch (e: RuntimeException) {
if (e.getMessage() != "FINALLY") {
return "FAIL in exception: " + e.getMessage()
} else {
return "CATCHED_EXCEPTION"
}
}
return "FAIL";
}
fun test4(h: Holder): String {
try {
val localResult = doCall2 (
{
h.value += "OK_LOCAL"
throw java.lang.RuntimeException("FAIL")
"OK_LOCAL"
},
{
h.value += ", OK_EXCEPTION"
throw java.lang.RuntimeException("EXCEPTION")
"OK_EXCEPTION"
},
{
h.value += ", OK_FINALLY"
"OK_FINALLY"
})
} catch (e: RuntimeException) {
if (e.getMessage() != "EXCEPTION") {
return "FAIL in exception: " + e.getMessage()
} else {
return "CATCHED_EXCEPTION"
}
}
return "FAIL";
}
fun box(): String {
var h = Holder()
val test0 = test0(h)
if (test0 != "CATCHED_EXCEPTION" || h.value != "OK_NON_LOCAL, OK_FINALLY") return "test0: ${test0}, holder: ${h.value}"
h = Holder()
val test1 = test1(h)
if (test1 != "CATCHED_EXCEPTION" || h.value != "OK_LOCAL, OK_EXCEPTION, OK_FINALLY") return "test1: ${test1}, holder: ${h.value}"
h = Holder()
val test2 = test2(h)
if (test2 != "OK_FINALLY" || h.value != "OK_LOCAL, OK_EXCEPTION, OK_FINALLY") return "test2: ${test2}, holder: ${h.value}"
h = Holder()
val test3 = test3(h)
if (test3 != "CATCHED_EXCEPTION" || h.value != "OK_LOCAL, OK_EXCEPTION, OK_FINALLY") return "test3: ${test3}, holder: ${h.value}"
h = Holder()
val test4 = test4(h)
if (test4 != "CATCHED_EXCEPTION" || h.value != "OK_LOCAL, OK_EXCEPTION, OK_FINALLY") return "test4: ${test4}, holder: ${h.value}"
return "OK"
}
@@ -0,0 +1,22 @@
package test
public inline fun <R> doCall(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R) : R {
try {
return block()
} catch (e: Exception) {
exception(e)
} finally {
return finallyBlock()
}
}
public inline fun <R> doCall2(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R) : R {
try {
return block()
} catch (e: Exception) {
exception(e)
} finally {
finallyBlock()
}
throw java.lang.RuntimeException("fail")
}
@@ -408,16 +408,179 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxCodegenT
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({TryFinally.CallSite.class, TryFinally.DeclSite.class, TryFinally.ExceptionTable.class})
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
public static class TryFinally extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInTryFinally() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("external.1.kt")
public void testExternal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/external.1.kt");
doTestMultiFileWithInlineCheck(fileName);
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite")
@TestDataPath("$PROJECT_ROOT")
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
public static class CallSite extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInCallSite() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("callSite.1.kt")
public void testCallSite() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSite.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite")
@TestDataPath("$PROJECT_ROOT")
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
public static class DeclSite extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInDeclSite() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("complex.1.kt")
public void testComplex() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/complex.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("intReturn.1.kt")
public void testIntReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturn.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("longReturn.1.kt")
public void testLongReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("nested.1.kt")
public void testNested() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/nested.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("returnInFinally.1.kt")
public void testReturnInFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInFinally.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("returnInTry.1.kt")
public void testReturnInTry() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTry.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("returnInTryAndFinally.1.kt")
public void testReturnInTryAndFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTryAndFinally.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("voidInlineFun.1.kt")
public void testVoidInlineFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("voidNonLocal.1.kt")
public void testVoidNonLocal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidNonLocal.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
public static class ExceptionTable extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInExceptionTable() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("break.1.kt")
public void testBreak() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/break.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("continue.1.kt")
public void testContinue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/continue.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("forInFinally.1.kt")
public void testForInFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("innerAndExternal.1.kt")
public void testInnerAndExternal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternal.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("innerAndExternalNested.1.kt")
public void testInnerAndExternalNested() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalNested.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("innerAndExternalSimple.1.kt")
public void testInnerAndExternalSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("nested.1.kt")
public void testNested() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("nestedWithReturns.1.kt")
public void testNestedWithReturns() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturns.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("nestedWithReturnsSimple.1.kt")
public void testNestedWithReturnsSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturnsSimple.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("noFinally.1.kt")
public void testNoFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/noFinally.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("severalCatchClause.1.kt")
public void testSeveralCatchClause() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/severalCatchClause.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("simpleThrow.1.kt")
public void testSimpleThrow() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/simpleThrow.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("throwInFinally.1.kt")
public void testThrowInFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
}
}
@@ -408,16 +408,179 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({TryFinally.CallSite.class, TryFinally.DeclSite.class, TryFinally.ExceptionTable.class})
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
public static class TryFinally extends AbstractCompileKotlinAgainstKotlinTest {
public void testAllFilesPresentInTryFinally() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("external.1.kt")
public void testExternal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/external.1.kt");
doBoxTestWithInlineCheck(fileName);
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite")
@TestDataPath("$PROJECT_ROOT")
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
public static class CallSite extends AbstractCompileKotlinAgainstKotlinTest {
public void testAllFilesPresentInCallSite() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("callSite.1.kt")
public void testCallSite() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSite.1.kt");
doBoxTestWithInlineCheck(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite")
@TestDataPath("$PROJECT_ROOT")
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
public static class DeclSite extends AbstractCompileKotlinAgainstKotlinTest {
public void testAllFilesPresentInDeclSite() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("complex.1.kt")
public void testComplex() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/complex.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("intReturn.1.kt")
public void testIntReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturn.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("longReturn.1.kt")
public void testLongReturn() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("nested.1.kt")
public void testNested() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/nested.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("returnInFinally.1.kt")
public void testReturnInFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInFinally.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("returnInTry.1.kt")
public void testReturnInTry() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTry.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("returnInTryAndFinally.1.kt")
public void testReturnInTryAndFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTryAndFinally.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("voidInlineFun.1.kt")
public void testVoidInlineFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("voidNonLocal.1.kt")
public void testVoidNonLocal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidNonLocal.1.kt");
doBoxTestWithInlineCheck(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(org.jetbrains.jet.JUnit3RunnerWithInners.class)
public static class ExceptionTable extends AbstractCompileKotlinAgainstKotlinTest {
public void testAllFilesPresentInExceptionTable() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("break.1.kt")
public void testBreak() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/break.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("continue.1.kt")
public void testContinue() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/continue.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("forInFinally.1.kt")
public void testForInFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("innerAndExternal.1.kt")
public void testInnerAndExternal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternal.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("innerAndExternalNested.1.kt")
public void testInnerAndExternalNested() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalNested.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("innerAndExternalSimple.1.kt")
public void testInnerAndExternalSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("nested.1.kt")
public void testNested() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("nestedWithReturns.1.kt")
public void testNestedWithReturns() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturns.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("nestedWithReturnsSimple.1.kt")
public void testNestedWithReturnsSimple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturnsSimple.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("noFinally.1.kt")
public void testNoFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/noFinally.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("severalCatchClause.1.kt")
public void testSeveralCatchClause() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/severalCatchClause.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("simpleThrow.1.kt")
public void testSimpleThrow() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/simpleThrow.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("throwInFinally.1.kt")
public void testThrowInFinally() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.1.kt");
doBoxTestWithInlineCheck(fileName);
}
}
}