Refactored packagename to net.sourceforge.phpdt.internal.compiler.ast
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / TryStatement.java
index d64dc60..59a804d 100644 (file)
@@ -1,18 +1,16 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v0.5 
+ * are made available under the terms of the Common Public License v1.0
  * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
  * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
 package net.sourceforge.phpdt.internal.compiler.ast;
 
-import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
-import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
-import net.sourceforge.phpdt.internal.compiler.codegen.ExceptionLabel;
+import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
 import net.sourceforge.phpdt.internal.compiler.flow.ExceptionHandlingFlowContext;
 import net.sourceforge.phpdt.internal.compiler.flow.FinallyFlowContext;
@@ -36,6 +34,8 @@ public class TryStatement extends Statement {
        BlockScope scope;
 
        public boolean subRoutineCannotReturn = true;
+       public UnconditionalFlowInfo subRoutineInits;
+       
        // should rename into subRoutineComplete to be set to false by default
 
        ReferenceBinding[] caughtExceptionTypes;
@@ -72,10 +72,10 @@ public class TryStatement extends Statement {
                        currentScope.methodScope().recordInitializationStates(flowInfo);
 
                if (anyExceptionVariable != null) {
-                       anyExceptionVariable.used = true;
+                       anyExceptionVariable.useFlag = LocalVariableBinding.USED;
                }
                if (returnAddressVariable != null) {
-                       returnAddressVariable.used = true;
+                       returnAddressVariable.useFlag = LocalVariableBinding.USED;
                }
                InsideSubRoutineFlowContext insideSubContext;
                FinallyFlowContext finallyContext;
@@ -88,16 +88,17 @@ public class TryStatement extends Statement {
                } else {
                        // analyse finally block first
                        insideSubContext = new InsideSubRoutineFlowContext(flowContext, this);
-                       subInfo =
+                       subInfo = 
                                finallyBlock
                                        .analyseCode(
                                                currentScope,
                                                finallyContext = new FinallyFlowContext(flowContext, finallyBlock),
                                                flowInfo.copy())
                                        .unconditionalInits();
-                       if (!((subInfo == FlowInfo.DeadEnd) || subInfo.isFakeReachable())) {
+                       if (subInfo.isReachable()) {
                                subRoutineCannotReturn = false;
                        }
+                       this.subRoutineInits = subInfo;
                }
                // process the try block in a context handling the local exceptions.
                ExceptionHandlingFlowContext handlingContext =
@@ -114,11 +115,11 @@ public class TryStatement extends Statement {
                        tryBlockExit = false;
                } else {
                        tryInfo = tryBlock.analyseCode(currentScope, handlingContext, flowInfo.copy());
-                       tryBlockExit = (tryInfo == FlowInfo.DeadEnd) || tryInfo.isFakeReachable();
+                       tryBlockExit = !tryInfo.isReachable();
                }
 
                // check unreachable catch blocks
-               handlingContext.complainIfUnusedExceptionHandlers(catchBlocks, scope, this);
+//             handlingContext.complainIfUnusedExceptionHandlers(catchBlocks, scope, this);
 
                // process the catch blocks - computing the minimal exit depth amongst try/catch
                if (catchArguments != null) {
@@ -126,7 +127,6 @@ public class TryStatement extends Statement {
                        catchExits = new boolean[catchCount = catchBlocks.length];
                        for (int i = 0; i < catchCount; i++) {
                                // keep track of the inits that could potentially have led to this exception handler (for final assignments diagnosis)
-                               ///*
                                FlowInfo catchInfo =
                                        flowInfo
                                                .copy()
@@ -145,16 +145,17 @@ public class TryStatement extends Statement {
                                "(uncheckedExceptionTypes notNil and: [uncheckedExceptionTypes at: index])
                                ifTrue: [catchInits addPotentialInitializationsFrom: tryInits]."
                                */
+                               // TODO: should only tag as unreachable if the catchblock cannot be reached
+                               //??? if (!handlingContext.initsOnException(caughtExceptionTypes[i]).isReachable()){
                                if (tryBlock.statements == null) {
-                                       catchInfo.markAsFakeReachable(true);
+                                       catchInfo.setReachMode(FlowInfo.UNREACHABLE);
                                }
                                catchInfo =
                                        catchBlocks[i].analyseCode(
                                                currentScope,
                                                insideSubContext == null ? flowContext : insideSubContext,
                                                catchInfo);
-                               catchExits[i] =
-                                       ((catchInfo == FlowInfo.DeadEnd) || catchInfo.isFakeReachable());
+                               catchExits[i] = !catchInfo.isReachable();
                                tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits());
                        }
                }
@@ -164,11 +165,15 @@ public class TryStatement extends Statement {
                        return tryInfo;
                }
 
+
                // we also need to check potential multiple assignments of final variables inside the finally block
                // need to include potential inits from returns inside the try/catch parts - 1GK2AOF
-               tryInfo.addPotentialInitializationsFrom(insideSubContext.initsOnReturn);
-               finallyContext.complainOnRedundantFinalAssignments(tryInfo, currentScope);
-               if (subInfo == FlowInfo.DeadEnd) {
+               finallyContext.complainOnRedundantFinalAssignments(
+                       tryInfo.isReachable() 
+                               ? (tryInfo.addPotentialInitializationsFrom(insideSubContext.initsOnReturn))
+                               : insideSubContext.initsOnReturn, 
+                       currentScope);
+               if (subInfo == FlowInfo.DEAD_END) {
                        mergedInitStateIndex =
                                currentScope.methodScope().recordInitializationStates(subInfo);
                        return subInfo;
@@ -189,216 +194,240 @@ public class TryStatement extends Statement {
         * Try statement code generation
         *
         */
-       public void generateCode(BlockScope currentScope, CodeStream codeStream) {
-
-               if ((bits & IsReachableMASK) == 0) {
-                       return;
-               }
-               if (tryBlock.isEmptyBlock()) {
-                       if (subRoutineStartLabel != null) {
-                               // since not passing the finallyScope, the block generation will exitUserScope(finallyScope)
-                               finallyBlock.generateCode(scope, codeStream);
-                       }
-                       // May loose some local variable initializations : affecting the local variable attributes
-                       if (mergedInitStateIndex != -1) {
-                               codeStream.removeNotDefinitelyAssignedVariables(
-                                       currentScope,
-                                       mergedInitStateIndex);
-                       }
-                       // no local bytecode produced so no need for position remembering
-                       return;
-               }
-               int pc = codeStream.position;
-               Label endLabel = new Label(codeStream);
-               boolean requiresNaturalJsr = false;
-
-               // preparing exception labels
-               int maxCatches;
-               ExceptionLabel[] exceptionLabels =
-                       new ExceptionLabel[maxCatches =
-                               catchArguments == null ? 0 : catchArguments.length];
-               for (int i = 0; i < maxCatches; i++) {
-                       boolean preserveCurrentHandler =
-                               (preserveExceptionHandler[i
-                                       / ExceptionHandlingFlowContext.BitCacheSize]
-                                               & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
-                                       != 0;
-                       if (preserveCurrentHandler) {
-                               exceptionLabels[i] =
-                                       new ExceptionLabel(
-                                               codeStream,
-                                               (ReferenceBinding) catchArguments[i].binding.type);
-                       }
-               }
-               ExceptionLabel anyExceptionLabel = null;
-               if (subRoutineStartLabel != null) {
-                       subRoutineStartLabel.codeStream = codeStream;
-                       anyExceptionLabel = new ExceptionLabel(codeStream, null);
+//     public void generateCode(BlockScope currentScope, CodeStream codeStream) {
+//
+//             if ((bits & IsReachableMASK) == 0) {
+//                     return;
+//             }
+//             if (tryBlock.isEmptyBlock()) {
+//                     if (subRoutineStartLabel != null) {
+//                             // since not passing the finallyScope, the block generation will exitUserScope(finallyScope)
+//                             finallyBlock.generateCode(scope, codeStream);
+//                     }
+//                     // May loose some local variable initializations : affecting the local variable attributes
+//                     if (mergedInitStateIndex != -1) {
+//                             codeStream.removeNotDefinitelyAssignedVariables(
+//                                     currentScope,
+//                                     mergedInitStateIndex);
+//                     }
+//                     // no local bytecode produced so no need for position remembering
+//                     return;
+//             }
+//             int pc = codeStream.position;
+//             Label endLabel = new Label(codeStream);
+//             boolean requiresNaturalJsr = false;
+//
+//             // preparing exception labels
+//             int maxCatches;
+//             ExceptionLabel[] exceptionLabels =
+//                     new ExceptionLabel[maxCatches =
+//                             catchArguments == null ? 0 : catchArguments.length];
+//             for (int i = 0; i < maxCatches; i++) {
+//                     boolean preserveCurrentHandler =
+//                             (preserveExceptionHandler[i
+//                                     / ExceptionHandlingFlowContext.BitCacheSize]
+//                                             & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
+//                                     != 0;
+//                     if (preserveCurrentHandler) {
+//                             exceptionLabels[i] =
+//                                     new ExceptionLabel(
+//                                             codeStream,
+//                                             (ReferenceBinding) catchArguments[i].binding.type);
+//                     }
+//             }
+//             ExceptionLabel anyExceptionLabel = null;
+//             if (subRoutineStartLabel != null) {
+//                     subRoutineStartLabel.codeStream = codeStream;
+//                     anyExceptionLabel = new ExceptionLabel(codeStream, null);
+//             }
+//             // generate the try block
+//             tryBlock.generateCode(scope, codeStream);
+//             boolean tryBlockHasSomeCode = codeStream.position != pc;
+//             // flag telling if some bytecodes were issued inside the try block
+//
+//             // natural exit: only if necessary
+//             boolean nonReturningSubRoutine =
+//                     (subRoutineStartLabel != null) && subRoutineCannotReturn;
+//             if ((!tryBlockExit) && tryBlockHasSomeCode) {
+//                     int position = codeStream.position;
+//                     if (nonReturningSubRoutine) {
+//                             codeStream.goto_(subRoutineStartLabel);
+//                     } else {
+//                             requiresNaturalJsr = true;
+//                             codeStream.goto_(endLabel);
+//                     }
+//                     codeStream.updateLastRecordedEndPC(position);
+//                     //goto is tagged as part of the try block
+//             }
+//             // place end positions of user-defined exception labels
+//             if (tryBlockHasSomeCode) {
+//                     for (int i = 0; i < maxCatches; i++) {
+//                             boolean preserveCurrentHandler =
+//                                     (preserveExceptionHandler[i     / ExceptionHandlingFlowContext.BitCacheSize]
+//                                                     & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
+//                                             != 0;
+//                             if (preserveCurrentHandler) {
+//                                     exceptionLabels[i].placeEnd();
+//                             }
+//                     }
+//                     /* generate sequence of handler, all starting by storing the TOS (exception
+//                     thrown) into their own catch variables, the one specified in the source
+//                     that must denote the handled exception.
+//                     */
+//                     if (catchArguments == null) {
+//                             if (anyExceptionLabel != null) {
+//                                     anyExceptionLabel.placeEnd();
+//                             }
+//                     } else {
+//                             for (int i = 0; i < maxCatches; i++) {
+//                                     boolean preserveCurrentHandler =
+//                                             (preserveExceptionHandler[i / ExceptionHandlingFlowContext.BitCacheSize]
+//                                                             & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
+//                                                     != 0;
+//                                     if (preserveCurrentHandler) {
+//                                             // May loose some local variable initializations : affecting the local variable attributes
+//                                             if (preTryInitStateIndex != -1) {
+//                                                     codeStream.removeNotDefinitelyAssignedVariables(
+//                                                             currentScope,
+//                                                             preTryInitStateIndex);
+//                                             }
+//                                             exceptionLabels[i].place();
+//                                             codeStream.incrStackSize(1);
+//                                             // optimizing the case where the exception variable is not actually used
+//                                             LocalVariableBinding catchVar;
+//                                             int varPC = codeStream.position;
+//                                             if ((catchVar = catchArguments[i].binding).resolvedPosition != -1) {
+//                                                     codeStream.store(catchVar, false);
+//                                                     catchVar.recordInitializationStartPC(codeStream.position);
+//                                                     codeStream.addVisibleLocalVariable(catchVar);
+//                                             } else {
+//                                                     codeStream.pop();
+//                                             }
+//                                             codeStream.recordPositionsFrom(varPC, catchArguments[i].sourceStart);
+//                                             // Keep track of the pcs at diverging point for computing the local attribute
+//                                             // since not passing the catchScope, the block generation will exitUserScope(catchScope)
+//                                             catchBlocks[i].generateCode(scope, codeStream);
+//                                     }
+//                                     if (i == maxCatches - 1) {
+//                                             if (anyExceptionLabel != null) {
+//                                                     anyExceptionLabel.placeEnd();
+//                                             }
+//                                             if (subRoutineStartLabel != null) {
+//                                                     if (!catchExits[i] && preserveCurrentHandler) {
+//                                                             requiresNaturalJsr = true;
+//                                                             codeStream.goto_(endLabel);
+//                                                     }
+//                                             }
+//                                     } else {
+//                                             if (!catchExits[i] && preserveCurrentHandler) {
+//                                                     if (nonReturningSubRoutine) {
+//                                                             codeStream.goto_(subRoutineStartLabel);
+//                                                     } else {
+//                                                             requiresNaturalJsr = true;
+//                                                             codeStream.goto_(endLabel);
+//                                                     }
+//                                             }
+//                                     }
+//                             }
+//                     }
+//                     // addition of a special handler so as to ensure that any uncaught exception (or exception thrown
+//                     // inside catch blocks) will run the finally block
+//                     int finallySequenceStartPC = codeStream.position;
+//                     if (subRoutineStartLabel != null) {
+//                             // the additional handler is doing: jsr finallyBlock and rethrow TOS-exception
+//                             anyExceptionLabel.place();
+//
+//                             if (preTryInitStateIndex != -1) {
+//                                     // reset initialization state, as for a normal catch block
+//                                     codeStream.removeNotDefinitelyAssignedVariables(
+//                                             currentScope,
+//                                             preTryInitStateIndex);
+//                             }
+//
+//                             codeStream.incrStackSize(1);
+//                             if (nonReturningSubRoutine) {
+//                                     codeStream.pop();
+//                                     // "if subroutine cannot return, no need to jsr/jump to subroutine since it will be entered in sequence
+//                             } else {
+//                                     codeStream.store(anyExceptionVariable, false);
+//                                     codeStream.jsr(subRoutineStartLabel);
+//                                     codeStream.load(anyExceptionVariable);
+//                                     codeStream.athrow();
+//                             }
+//                     }
+//                     // end of catch sequence, place label that will correspond to the finally block beginning, or end of statement
+//                     endLabel.place();
+//                     if (subRoutineStartLabel != null) {
+//                             if (nonReturningSubRoutine) {
+//                                     requiresNaturalJsr = false;
+//                             }
+//                             Label veryEndLabel = new Label(codeStream);
+//                             if (requiresNaturalJsr) {
+//                                     codeStream.jsr(subRoutineStartLabel);
+//                                     codeStream.goto_(veryEndLabel);
+//                             }
+//                             subRoutineStartLabel.place();
+//                             if (!nonReturningSubRoutine) {
+//                                     codeStream.incrStackSize(1);
+//                                     codeStream.store(returnAddressVariable, false);
+//                             }
+//                             codeStream.recordPositionsFrom(
+//                                     finallySequenceStartPC,
+//                                     finallyBlock.sourceStart);
+//                             // entire sequence for finally is associated to finally block
+//                             finallyBlock.generateCode(scope, codeStream);
+//                             if (!nonReturningSubRoutine) {
+//                                     int position = codeStream.position;
+//                                     codeStream.ret(returnAddressVariable.resolvedPosition);
+//                                     codeStream.updateLastRecordedEndPC(position);
+//                                     // the ret bytecode is part of the subroutine
+//                             }
+//                             if (requiresNaturalJsr) {
+//                                     veryEndLabel.place();
+//                             }
+//                     }
+//             } else {
+//                     // try block had no effect, only generate the body of the finally block if any
+//                     if (subRoutineStartLabel != null) {
+//                             finallyBlock.generateCode(scope, codeStream);
+//                     }
+//             }
+//             // May loose some local variable initializations : affecting the local variable attributes
+//             if (mergedInitStateIndex != -1) {
+//                     codeStream.removeNotDefinitelyAssignedVariables(
+//                             currentScope,
+//                             mergedInitStateIndex);
+//                     codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
+//             }
+//             codeStream.recordPositionsFrom(pc, this.sourceStart);
+//     }
+
+       public void resetStateForCodeGeneration() {
+               if (this.subRoutineStartLabel != null) {
+                       this.subRoutineStartLabel.resetStateForCodeGeneration();
                }
-               // generate the try block
-               tryBlock.generateCode(scope, codeStream);
-               boolean tryBlockHasSomeCode = codeStream.position != pc;
-               // flag telling if some bytecodes were issued inside the try block
-
-               // natural exit: only if necessary
-               boolean nonReturningSubRoutine =
-                       (subRoutineStartLabel != null) && subRoutineCannotReturn;
-               if ((!tryBlockExit) && tryBlockHasSomeCode) {
-                       int position = codeStream.position;
-                       if (nonReturningSubRoutine) {
-                               codeStream.goto_(subRoutineStartLabel);
-                       } else {
-                               requiresNaturalJsr = true;
-                               codeStream.goto_(endLabel);
-                       }
-                       codeStream.updateLastRecordedEndPC(position);
-                       //goto is tagged as part of the try block
-               }
-               // place end positions of user-defined exception labels
-               if (tryBlockHasSomeCode) {
-                       for (int i = 0; i < maxCatches; i++) {
-                               boolean preserveCurrentHandler =
-                                       (preserveExceptionHandler[i
-                                               / ExceptionHandlingFlowContext.BitCacheSize]
-                                                       & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
-                                               != 0;
-                               if (preserveCurrentHandler) {
-                                       exceptionLabels[i].placeEnd();
-                               }
-                       }
-                       /* generate sequence of handler, all starting by storing the TOS (exception
-                       thrown) into their own catch variables, the one specified in the source
-                       that must denote the handled exception.
-                       */
-                       if (catchArguments == null) {
-                               if (anyExceptionLabel != null) {
-                                       anyExceptionLabel.placeEnd();
-                               }
-                       } else {
-                               for (int i = 0; i < maxCatches; i++) {
-                                       boolean preserveCurrentHandler =
-                                               (preserveExceptionHandler[i
-                                                       / ExceptionHandlingFlowContext.BitCacheSize]
-                                                               & (1 << (i % ExceptionHandlingFlowContext.BitCacheSize)))
-                                                       != 0;
-                                       if (preserveCurrentHandler) {
-                                               // May loose some local variable initializations : affecting the local variable attributes
-                                               if (preTryInitStateIndex != -1) {
-                                                       codeStream.removeNotDefinitelyAssignedVariables(
-                                                               currentScope,
-                                                               preTryInitStateIndex);
-                                               }
-                                               exceptionLabels[i].place();
-                                               codeStream.incrStackSize(1);
-                                               // optimizing the case where the exception variable is not actually used
-                                               LocalVariableBinding catchVar;
-                                               int varPC = codeStream.position;
-                                               if ((catchVar = catchArguments[i].binding).resolvedPosition != -1) {
-                                                       codeStream.store(catchVar, false);
-                                                       catchVar.recordInitializationStartPC(codeStream.position);
-                                                       codeStream.addVisibleLocalVariable(catchVar);
-                                               } else {
-                                                       codeStream.pop();
-                                               }
-                                               codeStream.recordPositionsFrom(varPC, catchArguments[i].sourceStart);
-                                               // Keep track of the pcs at diverging point for computing the local attribute
-                                               // since not passing the catchScope, the block generation will exitUserScope(catchScope)
-                                               catchBlocks[i].generateCode(scope, codeStream);
-                                       }
-                                       if (i == maxCatches - 1) {
-                                               if (anyExceptionLabel != null) {
-                                                       anyExceptionLabel.placeEnd();
-                                               }
-                                               if (subRoutineStartLabel != null) {
-                                                       if (!catchExits[i] && preserveCurrentHandler) {
-                                                               requiresNaturalJsr = true;
-                                                               codeStream.goto_(endLabel);
-                                                       }
-                                               }
-                                       } else {
-                                               if (!catchExits[i] && preserveCurrentHandler) {
-                                                       if (nonReturningSubRoutine) {
-                                                               codeStream.goto_(subRoutineStartLabel);
-                                                       } else {
-                                                               requiresNaturalJsr = true;
-                                                               codeStream.goto_(endLabel);
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-                       // addition of a special handler so as to ensure that any uncaught exception (or exception thrown
-                       // inside catch blocks) will run the finally block
-                       int finallySequenceStartPC = codeStream.position;
-                       if (subRoutineStartLabel != null) {
-                               // the additional handler is doing: jsr finallyBlock and rethrow TOS-exception
-                               anyExceptionLabel.place();
-
-                               if (preTryInitStateIndex != -1) {
-                                       // reset initialization state, as for a normal catch block
-                                       codeStream.removeNotDefinitelyAssignedVariables(
-                                               currentScope,
-                                               preTryInitStateIndex);
-                               }
+       }       
+       public StringBuffer printStatement(int indent, StringBuffer output) {
+               printIndent(indent, output).append("try \n"); //$NON-NLS-1$
+               tryBlock.printStatement(indent + 1, output); //$NON-NLS-1$
 
-                               codeStream.incrStackSize(1);
-                               if (nonReturningSubRoutine) {
-                                       codeStream.pop();
-                                       // "if subroutine cannot return, no need to jsr/jump to subroutine since it will be entered in sequence
-                               } else {
-                                       codeStream.store(anyExceptionVariable, false);
-                                       codeStream.jsr(subRoutineStartLabel);
-                                       codeStream.load(anyExceptionVariable);
-                                       codeStream.athrow();
-                               }
-                       }
-                       // end of catch sequence, place label that will correspond to the finally block beginning, or end of statement
-                       endLabel.place();
-                       if (subRoutineStartLabel != null) {
-                               if (nonReturningSubRoutine) {
-                                       requiresNaturalJsr = false;
-                               }
-                               Label veryEndLabel = new Label(codeStream);
-                               if (requiresNaturalJsr) {
-                                       codeStream.jsr(subRoutineStartLabel);
-                                       codeStream.goto_(veryEndLabel);
-                               }
-                               subRoutineStartLabel.place();
-                               if (!nonReturningSubRoutine) {
-                                       codeStream.incrStackSize(1);
-                                       codeStream.store(returnAddressVariable, false);
-                               }
-                               codeStream.recordPositionsFrom(
-                                       finallySequenceStartPC,
-                                       finallyBlock.sourceStart);
-                               // entire sequence for finally is associated to finally block
-                               finallyBlock.generateCode(scope, codeStream);
-                               if (!nonReturningSubRoutine) {
-                                       int position = codeStream.position;
-                                       codeStream.ret(returnAddressVariable.resolvedPosition);
-                                       codeStream.updateLastRecordedEndPC(position);
-                                       // the ret bytecode is part of the subroutine
-                               }
-                               if (requiresNaturalJsr) {
-                                       veryEndLabel.place();
-                               }
-                       }
-               } else {
-                       // try block had no effect, only generate the body of the finally block if any
-                       if (subRoutineStartLabel != null) {
-                               finallyBlock.generateCode(scope, codeStream);
+               //catches
+               if (catchBlocks != null)
+                       for (int i = 0; i < catchBlocks.length; i++) {
+                                       output.append('\n');
+                                       printIndent(indent, output).append("catch ("); //$NON-NLS-1$
+                                       catchArguments[i].print(0, output).append(") "); //$NON-NLS-1$
+                                       catchBlocks[i].printStatement(indent + 1, output);
                        }
+               //finally
+               if (finallyBlock != null) {
+                       output.append('\n');
+                       printIndent(indent, output).append("finally\n"); //$NON-NLS-1$
+                       finallyBlock.printStatement(indent + 1, output);
                }
-               // May loose some local variable initializations : affecting the local variable attributes
-               if (mergedInitStateIndex != -1) {
-                       codeStream.removeNotDefinitelyAssignedVariables(
-                               currentScope,
-                               mergedInitStateIndex);
-                       codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
-               }
-               codeStream.recordPositionsFrom(pc, this.sourceStart);
-       }
 
+               return output;
+       }
        public void resolve(BlockScope upperScope) {
 
                // special scope for secret locals optimization.        
@@ -415,7 +444,7 @@ public class TryStatement extends Statement {
                        // provision for returning and forcing the finally block to run
                        MethodScope methodScope = scope.methodScope();
 
-                       // the type does not matter as long as its not a normal base type
+                       // the type does not matter as long as it is not a base type
                        this.returnAddressVariable =
                                new LocalVariableBinding(SecretReturnName, upperScope.getJavaLangObject(), AccDefault, false);
                        finallyScope.addLocalVariable(returnAddressVariable);
@@ -472,9 +501,9 @@ public class TryStatement extends Statement {
                        for (int i = 0; i < length; i++) {
                                caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i];
                                for (int j = 0; j < i; j++) {
-                                       if (BlockScope.areTypesCompatible(caughtExceptionTypes[i], argumentTypes[j])) {
+                                       if (caughtExceptionTypes[i].isCompatibleWith(argumentTypes[j])) {
                                                scope.problemReporter().wrongSequenceOfExceptionTypesError(this, i, j);
-                                               return;
+                                               // cannot return - since may still proceed if unreachable code is ignored (21203)
                                        }
                                }
                        }
@@ -518,7 +547,7 @@ public class TryStatement extends Statement {
        }
 
        public void traverse(
-               IAbstractSyntaxTreeVisitor visitor,
+           ASTVisitor visitor,
                BlockScope blockScope) {
 
                if (visitor.visit(this, blockScope)) {
@@ -534,4 +563,4 @@ public class TryStatement extends Statement {
                }
                visitor.endVisit(this, blockScope);
        }
-}
\ No newline at end of file
+}