diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index d28c5c02ce2..9c8aa0c5a76 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -52,6 +52,8 @@ public class ExpressionCodegen extends JetVisitor { private static final Type OBJECT_TYPE = Type.getType(Object.class); private static final Type ITERATOR_TYPE = Type.getType(Iterator.class); + private static final Type THROWABLE_TYPE = Type.getType(Throwable.class); + private static final Type RANGE_TYPE = Type.getType(Range.class); private static final Type INT_RANGE_TYPE = Type.getType(IntRange.class); private static final Type JET_OBJECT_TYPE = Type.getType(JetObject.class); @@ -1246,14 +1248,15 @@ public class ExpressionCodegen extends JetVisitor { @Override public void visitTryExpression(JetTryExpression expression) { - if (expression.getFinallyBlock() != null) { - throw new UnsupportedOperationException("finally block in try/catch not yet supported"); - } Label tryStart = new Label(); v.mark(tryStart); gen(expression.getTryBlock(), Type.VOID_TYPE); Label tryEnd = new Label(); v.mark(tryEnd); + JetFinallySection finallyBlock = expression.getFinallyBlock(); + if (finallyBlock != null) { + gen(finallyBlock.getFinalExpression(), Type.VOID_TYPE); + } Label end = new Label(); v.goTo(end); // TODO don't generate goto if there's no code following try/catch for (JetCatchClause clause : expression.getCatchClauses()) { @@ -1272,6 +1275,22 @@ public class ExpressionCodegen extends JetVisitor { myMap.leave(descriptor); v.visitTryCatchBlock(tryStart, tryEnd, clauseStart, descriptorType.getInternalName()); } + if (finallyBlock != null) { + Label finallyStart = new Label(); + v.mark(finallyStart); + + int index = myMap.enterTemp(); + v.store(index, THROWABLE_TYPE); + + gen(finallyBlock.getFinalExpression(), Type.VOID_TYPE); + + v.load(index, THROWABLE_TYPE); + v.athrow(); + + myMap.leaveTemp(); + + v.visitTryCatchBlock(tryStart, tryEnd, finallyStart, null); + } v.mark(end); } diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index e45f4a34e6d..311924650b7 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -1,11 +1,10 @@ package org.jetbrains.jet.codegen; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.types.*; +import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -81,17 +80,16 @@ public class FunctionCodegen { } else { bodyExpression.accept(codegen); - generateReturn(mv, bodyExpression, codegen); + generateReturn(mv, bodyExpression, codegen, jvmSignature); } mv.visitMaxs(0, 0); mv.visitEnd(); } } - private void generateReturn(MethodVisitor mv, JetExpression bodyExpression, ExpressionCodegen codegen) { + private void generateReturn(MethodVisitor mv, JetExpression bodyExpression, ExpressionCodegen codegen, Method jvmSignature) { if (!endsWithReturn(bodyExpression)) { - final JetType expressionType = bindingContext.getExpressionType(bodyExpression); - if (expressionType == null || expressionType.equals(JetStandardClasses.getUnitType())) { + if (jvmSignature.getReturnType() == Type.VOID_TYPE) { mv.visitInsn(Opcodes.RETURN); } else { diff --git a/idea/testData/codegen/controlStructures/tryFinally.jet b/idea/testData/codegen/controlStructures/tryFinally.jet new file mode 100644 index 00000000000..2108c83b5c0 --- /dev/null +++ b/idea/testData/codegen/controlStructures/tryFinally.jet @@ -0,0 +1,9 @@ +fun f(sb: StringBuilder, s: String): Unit { + try { + sb.append("foo"); + sb.append(Integer.parseInt(s)); + } + finally { + sb.append("bar"); + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index e26b4a608b0..8d7e06b291c 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -9,8 +9,13 @@ import java.util.List; * @author yole */ public class ControlStructuresTest extends CodegenTestCase { + @Override + protected String getPrefix() { + return "controlStructures"; + } + public void testIf() throws Exception { - loadFile("controlStructures/if.jet"); + loadFile(); System.out.println(generateToText()); final Method main = generateFunction(); @@ -19,7 +24,7 @@ public class ControlStructuresTest extends CodegenTestCase { } public void testSingleBranchIf() throws Exception { - loadFile("controlStructures/singleBranchIf.jet"); + loadFile(); System.out.println(generateToText()); final Method main = generateFunction(); @@ -49,7 +54,7 @@ public class ControlStructuresTest extends CodegenTestCase { } public void testContinue() throws Exception { - loadFile("controlStructures/continue.jet"); + loadFile(); System.out.println(generateToText()); final Method main = generateFunction(); assertEquals(3, main.invoke(null, 4)); @@ -57,7 +62,7 @@ public class ControlStructuresTest extends CodegenTestCase { } public void testIfNoElse() throws Exception { - loadFile("controlStructures/ifNoElse.jet"); + loadFile(); System.out.println(generateToText()); final Method main = generateFunction(); assertEquals(5, main.invoke(null, 5, true)); @@ -72,7 +77,7 @@ public class ControlStructuresTest extends CodegenTestCase { } public void testFor() throws Exception { - loadFile("controlStructures/for.jet"); + loadFile(); System.out.println(generateToText()); final Method main = generateFunction(); List args = Arrays.asList("IntelliJ", " ", "IDEA"); @@ -80,7 +85,7 @@ public class ControlStructuresTest extends CodegenTestCase { } public void testForInArray() throws Exception { - loadFile("controlStructures/forInArray.jet"); + loadFile(); System.out.println(generateToText()); final Method main = generateFunction(); String[] args = new String[] { "IntelliJ", " ", "IDEA" }; @@ -102,10 +107,29 @@ public class ControlStructuresTest extends CodegenTestCase { } public void testTryCatch() throws Exception { - loadFile("controlStructures/tryCatch.jet"); + loadFile(); System.out.println(generateToText()); final Method main = generateFunction(); assertEquals("no message", main.invoke(null, "0")); assertEquals("For input string: \"a\"", main.invoke(null, "a")); } + + public void testTryFinally() throws Exception { + loadFile(); + System.out.println(generateToText()); + final Method main = generateFunction(); + StringBuilder sb = new StringBuilder(); + main.invoke(null, sb, "9"); + assertEquals("foo9bar", sb.toString()); + sb = new StringBuilder(); + boolean caught = false; + try { + main.invoke(null, sb, "x"); + } + catch(InvocationTargetException e) { + caught = e.getTargetException() instanceof NumberFormatException; + } + assertTrue(caught); + assertEquals("foobar", sb.toString()); + } }