diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java index c3baae257ab..12e058b5d8a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java @@ -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); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java index ab19b5bdffb..409cdb89d0c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java @@ -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 infos = MethodInliner.processReturns(adapter, labelOwner, true, null); + List 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 insertPoints) { + public void generateAndInsertFinallyBlocks(MethodNode intoNode, List 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(), diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java index 7d7fef0be4f..a79952d2779 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java @@ -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 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); + } + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InternalFinallyBlockInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InternalFinallyBlockInliner.java new file mode 100644 index 00000000000..54632c9ef8e --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InternalFinallyBlockInliner.java @@ -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 inlineFunTryBlockInfo = new ArrayList(); + 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 inlineFunTryBlockInfo; + + private final ListMultimap tryBlockStarts = LinkedListMultimap.create(); + + private final ListMultimap 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 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 coveringTryCatchBlocks = new Stack(); + 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 clusters = InlinePackage.doClustering(coveringTryCatchBlocks); + ListIterator tryCatchBlockIterator = clusters.listIterator(clusters.size()); + //Reverse visiting cause innermost tryCatchBlocks in the end + while (tryCatchBlockIterator.hasPrevious()) { + TryBlockCluster originalFinallyCluster = tryCatchBlockIterator.previous(); + List clusterBlocks = originalFinallyCluster.getBlocks(); + TryCatchBlockNodeInfo originalFinallyBlock = clusterBlocks.get(0); + + FinallyBlockInfo finallyInfo = findFinallyBlockBody(originalFinallyBlock, inlineFunTryBlockInfo); + if (finallyInfo == null) continue; + + instructions.resetLabels(); + + List 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 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 rememberOriginalLabelNodes(@NotNull FinallyBlockInfo finallyInfo) { + Set labelsInsideFinally = new HashSet(); + 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 coveringTryBlocks, + @Nullable AbstractInsnNode nextPrev, + @NotNull List clusterBlocks, + @NotNull Label newFinallyStart, + @NotNull Label newFinallyEnd, + @NotNull List 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 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 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 tryCatchBlocks + ) { + List sameDefaultHandler = new ArrayList(); + 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 findTryCatchBlocksInlinedInFinally(@NotNull FinallyBlockInfo finallyInfo) { + List result = new ArrayList(); + Map processedBlocks = new HashMap(); + for (AbstractInsnNode curInstr = finallyInfo.startIns; curInstr != finallyInfo.endInsExclusive; curInstr = curInstr.getNext()) { + if (!(curInstr instanceof LabelNode)) continue; + + LabelNode curLabel = (LabelNode) curInstr; + List 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 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 comp = new Comparator() { + @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); + } +} diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MaxCalcNode.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MaxCalcNode.java index 999787c4712..46920388b4a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MaxCalcNode.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MaxCalcNode.java @@ -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 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 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; } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java index 245df734c73..2eb06564c88 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java @@ -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 currentInvokes = new LinkedList(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 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 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 processReturns(@NotNull MethodNode node, @NotNull LabelOwner labelOwner, boolean remapReturn, Label endLabel) { if (!remapReturn) { return Collections.emptyList(); } - List result = new ArrayList(); + List result = new ArrayList(); 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; } } + } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/TryBlockClustering.kt b/compiler/backend/src/org/jetbrains/jet/codegen/inline/TryBlockClustering.kt new file mode 100644 index 00000000000..9ad28eef769 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/TryBlockClustering.kt @@ -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) + + +fun doClustering(blocks: List) : List { + [data] class TryBlockInterval(val startLabel: LabelNode, val endLabel: LabelNode) + + val clusters = linkedMapOf() + 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(); +} + diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/external.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSite.1.kt similarity index 100% rename from compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/external.1.kt rename to compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSite.1.kt diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/external.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSite.2.kt similarity index 100% rename from compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/external.2.kt rename to compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/callSite/callSite.2.kt diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/complex.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/complex.1.kt new file mode 100644 index 00000000000..e0eb0efafca --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/complex.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/complex.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/complex.2.kt new file mode 100644 index 00000000000..f3aeaae15d3 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/complex.2.kt @@ -0,0 +1,9 @@ +package test + +public inline fun doCall(block: ()-> R, finallyLambda: ()-> Unit) : R { + try { + return block() + } finally { + finallyLambda() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturn.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturn.1.kt new file mode 100644 index 00000000000..59892ae123e --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturn.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturn.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturn.2.kt new file mode 100644 index 00000000000..6c59dc1a204 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/intReturn.2.kt @@ -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 doCall2(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R, res: R) : R { + try { + return block() + } catch (e: Exception) { + exception(e) + } finally { + finallyBlock() + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.1.kt new file mode 100644 index 00000000000..6bd511905f8 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.2.kt new file mode 100644 index 00000000000..322e42e5e2c --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/longReturn.2.kt @@ -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 doCall2(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R, res: R) : R { + try { + return block() + } catch (e: Exception) { + exception(e) + } finally { + finallyBlock() + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/nested.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/nested.1.kt new file mode 100644 index 00000000000..2d5cc745ec0 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/nested.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/nested.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/nested.2.kt new file mode 100644 index 00000000000..8888bb5e342 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/nested.2.kt @@ -0,0 +1,14 @@ +package test + +public inline fun doCall(block: ()-> Unit, finallyBlock1: ()-> Unit, finallyBlock2: ()-> Unit) { + try { + try { + block() + } + finally { + finallyBlock1() + } + } finally { + finallyBlock2() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInFinally.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInFinally.1.kt new file mode 100644 index 00000000000..0f7ad104084 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInFinally.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInFinally.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInFinally.2.kt new file mode 100644 index 00000000000..cd15844d50f --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInFinally.2.kt @@ -0,0 +1,9 @@ +package test + +public inline fun doCall(block: ()-> R, finallyBlock: ()-> R) : R { + try { + block() + } finally { + return finallyBlock() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTry.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTry.1.kt new file mode 100644 index 00000000000..c91bc8bda10 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTry.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTry.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTry.2.kt new file mode 100644 index 00000000000..e65ab6b6283 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTry.2.kt @@ -0,0 +1,9 @@ +package test + +public inline fun doCall(block: ()-> R, finallyBlock: ()-> Unit) : R { + try { + return block() + } finally { + finallyBlock() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTryAndFinally.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTryAndFinally.1.kt new file mode 100644 index 00000000000..9bab28b5ff1 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTryAndFinally.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTryAndFinally.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTryAndFinally.2.kt new file mode 100644 index 00000000000..9d8cbea9edc --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/returnInTryAndFinally.2.kt @@ -0,0 +1,9 @@ +package test + +public inline fun doCall(block: ()-> R, finallyBlock: ()-> R) : R { + try { + return block() + } finally { + return finallyBlock() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.1.kt new file mode 100644 index 00000000000..16101fd4288 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.2.kt new file mode 100644 index 00000000000..849b9d737a3 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidInlineFun.2.kt @@ -0,0 +1,9 @@ +package test + +public inline fun doCall(block: ()-> R, finallyBlock: ()-> Unit) { + try { + block() + } finally { + finallyBlock() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidNonLocal.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidNonLocal.1.kt new file mode 100644 index 00000000000..d3d4ce6ec29 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidNonLocal.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidNonLocal.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidNonLocal.2.kt new file mode 100644 index 00000000000..e65ab6b6283 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/declSite/voidNonLocal.2.kt @@ -0,0 +1,9 @@ +package test + +public inline fun doCall(block: ()-> R, finallyBlock: ()-> Unit) : R { + try { + return block() + } finally { + finallyBlock() + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/break.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/break.1.kt new file mode 100644 index 00000000000..ba10a41daf0 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/break.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/break.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/break.2.kt new file mode 100644 index 00000000000..31037a701ec --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/break.2.kt @@ -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 +//} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/continue.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/continue.1.kt new file mode 100644 index 00000000000..e95ac2e88d5 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/continue.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/continue.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/continue.2.kt new file mode 100644 index 00000000000..ed977ef927d --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/continue.2.kt @@ -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 +//} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.1.kt new file mode 100644 index 00000000000..957fe245ce6 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.2.kt new file mode 100644 index 00000000000..afa491375fa --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/forInFinally.2.kt @@ -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 +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternal.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternal.1.kt new file mode 100644 index 00000000000..b6c7a04dce6 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternal.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternal.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternal.2.kt new file mode 100644 index 00000000000..b7601296aed --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternal.2.kt @@ -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 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") +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalNested.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalNested.1.kt new file mode 100644 index 00000000000..2f87484f4ae --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalNested.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalNested.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalNested.2.kt new file mode 100644 index 00000000000..d5d44c569ab --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalNested.2.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.1.kt new file mode 100644 index 00000000000..6e1ae4cda9e --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.2.kt new file mode 100644 index 00000000000..fe1ad74bedc --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/innerAndExternalSimple.2.kt @@ -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 +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.1.kt new file mode 100644 index 00000000000..3a38a10b715 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.2.kt new file mode 100644 index 00000000000..d5d44c569ab --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nested.2.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturns.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturns.1.kt new file mode 100644 index 00000000000..9dca693f6ea --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturns.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturns.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturns.2.kt new file mode 100644 index 00000000000..884af8f5a2b --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturns.2.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturnsSimple.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturnsSimple.1.kt new file mode 100644 index 00000000000..32578318d1d --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturnsSimple.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturnsSimple.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturnsSimple.2.kt new file mode 100644 index 00000000000..4e5daf86c27 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/nestedWithReturnsSimple.2.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/noFinally.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/noFinally.1.kt new file mode 100644 index 00000000000..7f6a189f1bb --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/noFinally.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/noFinally.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/noFinally.2.kt new file mode 100644 index 00000000000..d44c53a3472 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/noFinally.2.kt @@ -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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/severalCatchClause.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/severalCatchClause.1.kt new file mode 100644 index 00000000000..87928da24d7 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/severalCatchClause.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/severalCatchClause.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/severalCatchClause.2.kt new file mode 100644 index 00000000000..b7601296aed --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/severalCatchClause.2.kt @@ -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 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") +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/simpleThrow.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/simpleThrow.1.kt new file mode 100644 index 00000000000..b6d442fecb8 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/simpleThrow.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/simpleThrow.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/simpleThrow.2.kt new file mode 100644 index 00000000000..d23f1e56beb --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/simpleThrow.2.kt @@ -0,0 +1,12 @@ +package test + +public inline fun doCall(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R, res: R) : R { + try { + return block() + } catch (e: Exception) { + exception(e) + } finally { + finallyBlock() + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.1.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.1.kt new file mode 100644 index 00000000000..f23941a391e --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.1.kt @@ -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" +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.2.kt new file mode 100644 index 00000000000..9021841182a --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/tryFinally/exceptionTable/throwInFinally.2.kt @@ -0,0 +1,22 @@ +package test + +public inline fun doCall(block: ()-> R, exception: (e: Exception)-> Unit, finallyBlock: ()-> R) : R { + try { + return block() + } catch (e: Exception) { + exception(e) + } finally { + return finallyBlock() + } +} + +public inline fun 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") +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java index 902beede005..687f0ce3edb 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxInlineCodegenTestGenerated.java @@ -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); + } + } } diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java index 0c97c0012cb..1d37956aea6 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -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); + } + } }