// $Id: body.cpp,v 1.103 2004/08/18 08:49:15 elliott-oss Exp $
//
// This software is subject to the terms of the IBM Jikes Compiler
// License Agreement available at the following URL:
// http://ibm.com/developerworks/opensource/jikes.
// Copyright (C) 1996, 2004 IBM Corporation and others.  All Rights Reserved.
// You must accept the terms of that agreement to use this software.
//

#include "platform.h"
#include "semantic.h"
#include "control.h"
#include "option.h"
#include "stream.h"

#ifdef HAVE_JIKES_NAMESPACE
namespace Jikes { // Open namespace Jikes block
#endif

void Semantic::ProcessBlockStatements(AstBlock* block_body)
{
    //
    // An empty block that is not a switch block can complete normally
    // iff it is reachable. A nonempty block that is not a switch
    // block can complete normally iff the last statement in it can
    // complete normally.
    //
    if (block_body -> NumStatements() == 0)
        block_body -> can_complete_normally = block_body -> is_reachable;
    else
    {
        //
        // The first statement in a nonempty block that is not a
        // switch block is reachable iff the block is reachable.
        // Every other statement S in a nonempty block that is not a
        // switch block is reachable iff the statement preceeding S
        // can complete normally.
        //
        AstStatement* statement = block_body -> Statement(0);
        statement -> is_reachable = block_body -> is_reachable;
        AstStatement* first_unreachable_statement =
            (AstStatement*) (statement -> is_reachable ? NULL : statement);
        ProcessStatement(statement);
        for (unsigned i = 1; i < block_body -> NumStatements(); i++)
        {
            AstStatement* previous_statement = statement;
            statement = block_body -> Statement(i);
            statement -> is_reachable =
                previous_statement -> can_complete_normally;
            if (! statement -> is_reachable &&
                first_unreachable_statement == NULL)
            {
                first_unreachable_statement = statement;
            }
            ProcessStatement(statement);
        }

        if (statement -> can_complete_normally)
            block_body -> can_complete_normally = true;

        //
        // If we have one or more unreachable statements that are contained in
        // a reachable block then issue message. (If the enclosing block is
        // not reachable the message will be issued later for the enclosing
        // block.)
        //
        if (first_unreachable_statement &&
            LocalBlockStack().TopBlock() -> is_reachable)
        {
            if (first_unreachable_statement == statement)
            {
                ReportSemError(SemanticError::UNREACHABLE_STATEMENT,
                               statement);
            }
            else
            {
                ReportSemError(SemanticError::UNREACHABLE_STATEMENTS,
                               first_unreachable_statement -> LeftToken(),
                               statement -> RightToken());
            }
        }

        //
        // If an enclosed block has a higher max_variable_index than the
        // current block, update max_variable_index in the current_block,
        // accordingly.
        //
        BlockSymbol* block = block_body -> block_symbol;
        if (block -> max_variable_index <
            LocalBlockStack().TopMaxEnclosedVariableIndex())
        {
            block -> max_variable_index =
                LocalBlockStack().TopMaxEnclosedVariableIndex();
        }
    }
}


void Semantic::ProcessBlock(Ast* stmt)
{
    AstBlock* block_body = (AstBlock*) stmt;

    AstBlock* enclosing_block = LocalBlockStack().TopBlock();

    //
    // Guess that the number of elements will not exceed the number of
    // statements + 3. The +3 takes into account one label + one ForInit
    // declaration and one extra something else.
    //
    int table_size = block_body -> NumStatements() + 3;
    BlockSymbol* block =
        LocalSymbolTable().Top() -> InsertBlockSymbol(table_size);
    //
    // enclosing_block is not present only when we are processing the block
    // of a static initializer
    //
    block -> max_variable_index =
        enclosing_block
        ? enclosing_block -> block_symbol -> max_variable_index : 1;
    LocalSymbolTable().Push(block -> Table());

    block_body -> block_symbol = block;
    block_body -> nesting_level = LocalBlockStack().Size();
    LocalBlockStack().Push(block_body);

    //
    // Note that in constructing the Ast, the parser encloses each
    // labeled statement in its own block. Therefore the declaration
    // of this label will not conflict with the declaration of another
    // label with the same name declared at the same nesting level.
    //
    // For example, the following sequence of statements is legal:
    //
    //     l: a = b;
    //     l: b = c;
    //
    if (block_body -> label_opt != BAD_TOKEN)
    {
        NameSymbol* name_symbol =
            lex_stream -> NameSymbol(block_body -> label_opt);
        if (LocalSymbolTable().FindLabelSymbol(name_symbol))
        {
            ReportSemError(SemanticError::DUPLICATE_LABEL,
                           block_body -> label_opt,
                           name_symbol -> Name());
        }
        else
        {
            LabelSymbol* label =
                LocalSymbolTable().Top() -> InsertLabelSymbol(name_symbol);
            label -> block = block_body;
            label -> nesting_level = block_body -> nesting_level;
        }
    }

    ProcessBlockStatements(block_body);

    LocalBlockStack().Pop();
    LocalSymbolTable().Pop();

    //
    // Update the information for the block that immediately encloses the
    // current block.
    //
    if (enclosing_block && (LocalBlockStack().TopMaxEnclosedVariableIndex() <
                            block -> max_variable_index))
    {
        LocalBlockStack().TopMaxEnclosedVariableIndex() =
            block -> max_variable_index;
    }

    block -> CompressSpace(); // space optimization
}


void Semantic::WarnOfAccessibleFieldWithName(SemanticError::SemanticErrorKind problem,
                                             AstVariableDeclaratorId* name,
                                             NameSymbol* name_symbol,
                                             bool is_static)
{
    TypeSymbol* this_type = ThisType();
    for (TypeSymbol* type = this_type; type != 0; type = type -> super)
    {
        //
        // Try to find a variable with the same name_symbol, first in the
        // type itself, then in any of its implemented interfaces.
        //
        VariableSymbol* variable = type -> FindVariableSymbol(name_symbol);
        for (unsigned i = 0; variable == 0 && i < type -> NumInterfaces(); ++i)
        {
            variable = type -> Interface(i) -> FindVariableSymbol(name_symbol);
        }

        //
        // Warn if we found an accessible field with the same name_symbol.
        //
        if (variable && MemberAccessCheck(this_type, variable, 0))
        {
            // Ignore static variables if we're looking for non-static,
            // and non-static if we're looking for static.
            if (variable -> ACC_STATIC() != is_static)
            {
                continue;
            }

            TypeSymbol* containing_type = variable -> ContainingType();
            ReportSemError(problem,
                           name -> identifier_token,
                           name_symbol -> Name(),
                           containing_type -> ContainingPackageName(),
                           containing_type -> ExternalName());
            return;
        }
    }
}


void Semantic::ProcessLocalVariableStatement(Ast* stmt)
{
    AstLocalVariableStatement* local_decl = (AstLocalVariableStatement*) stmt;
    ProcessType(local_decl -> type);
    TypeSymbol* field_type = local_decl -> type -> symbol;
    AccessFlags access_flags = ProcessLocalModifiers(local_decl);

    for (unsigned i = 0; i < local_decl -> NumVariableDeclarators(); i++)
    {
        AstVariableDeclarator* variable_declarator =
            local_decl -> VariableDeclarator(i);
        AstVariableDeclaratorId* name =
            variable_declarator -> variable_declarator_name;
        NameSymbol* name_symbol =
            lex_stream -> NameSymbol(name -> identifier_token);

        //
        // According to JLS2 14.4.2, only check for a duplicate in
        // the local class scope; don't worry about enclosing classes
        //
        VariableSymbol* duplicate =
            LocalSymbolTable().FindVariableSymbol(name_symbol);
        if (duplicate)
        {
            ReportSemError(SemanticError::DUPLICATE_LOCAL_VARIABLE_DECLARATION,
                           name -> identifier_token, name_symbol -> Name(),
                           duplicate -> FileLoc());
        }
        else
        {
            WarnOfAccessibleFieldWithName(SemanticError::LOCAL_SHADOWS_FIELD,
                                          name, name_symbol, ThisMethod() -> ACC_STATIC());
            AstBlock* block = LocalBlockStack().TopBlock();
            SymbolTable* table;
            if (block -> Tag() == AstBlock::SWITCH)
            {
                //
                // Local variables declared in a switch statement are in scope
                // for the entire switch, rather than the nearest label (unlike
                // local classes).  Hence, we have to check if the top block is
                // a switch statement, and use the next level up if so.
                //
                block = LocalBlockStack()[LocalBlockStack().Size() - 2];
                table = LocalSymbolTable()[LocalSymbolTable().Size() - 2];
            }
            else table = LocalSymbolTable().Top();
            VariableSymbol* symbol =
                table -> InsertVariableSymbol(name_symbol);
            variable_declarator -> symbol = symbol;

            unsigned dims =
                field_type -> num_dimensions + name -> NumBrackets();
            symbol -> SetType(field_type -> GetArrayType(this, dims));
            symbol -> SetFlags(access_flags);
            symbol -> SetOwner(ThisMethod());
            symbol -> declarator = variable_declarator;
            symbol -> SetLocation();
            symbol -> SetLocalVariableIndex(block -> block_symbol ->
                                            max_variable_index++);
            if (control.IsDoubleWordType(symbol -> Type()))
                block -> block_symbol -> max_variable_index++;

            //
            // Warn against unconventional names. Note that there's no
            // strong convention for final local variables, so we allow
            // both the usual style for local variables and the usual
            // style for constant fields. We recommend the local variable
            // style, somewhat arbitrarily.
            //
            if (! symbol -> ACC_FINAL() &&
                name_symbol -> IsBadStyleForVariable())
            {
                ReportSemError(SemanticError::UNCONVENTIONAL_VARIABLE_NAME,
                               name -> identifier_token, name_symbol -> Name());
            }
            else if (symbol -> ACC_FINAL() &&
                     name_symbol -> IsBadStyleForVariable() &&
                     name_symbol -> IsBadStyleForConstantField())
            {
                ReportSemError(SemanticError::UNCONVENTIONAL_VARIABLE_NAME,
                               name -> identifier_token, name_symbol -> Name());
            }
            
            ProcessVariableInitializer(variable_declarator);
        }
    }

    //
    // A local variable declaration statement can complete normally
    // iff it is reachable.
    //
    local_decl -> can_complete_normally = local_decl -> is_reachable;
}


void Semantic::ProcessExpressionStatement(Ast* stmt)
{
    AstExpressionStatement* expression_statement =
        (AstExpressionStatement*) stmt;

    ProcessExpression(expression_statement -> expression);

    //
    // An expression statement can complete normally iff it is reachable.
    //
    expression_statement -> can_complete_normally =
        expression_statement -> is_reachable;
}


void Semantic::ProcessSynchronizedStatement(Ast* stmt)
{
    AstSynchronizedStatement* synchronized_statement =
        (AstSynchronizedStatement*) stmt;

    //
    // Notice that in the case of a complex string constant, it is
    // vital to inline correctly; otherwise, we would not be using
    // the correct object as the monitor.
    //
    ProcessExpressionOrStringConstant(synchronized_statement -> expression);

    synchronized_statement -> block -> is_reachable =
        synchronized_statement -> is_reachable;

    if (synchronized_statement -> expression -> Type() -> Primitive() ||
        synchronized_statement -> expression -> symbol == control.null_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_REFERENCE,
                       synchronized_statement -> expression,
                       synchronized_statement -> expression -> Type() -> Name());
    }

    AstBlock* enclosing_block = LocalBlockStack().TopBlock();
    AstBlock* block_body = synchronized_statement -> block;

    //
    // Synchronized blocks require one special local variable slot for the
    // monitor. However, since a try-finally may require up to four slots, we
    // reserve them all at this time.  Otherwise, the sequence {synchronized;
    // variable declaration; try-finally} within the same enclosing block will
    // cause a VerifyError. The VM should not care if some of these special
    // slots are unused.
    //
    // TODO: Is it worth optimizing this and try-finally to avoid wasting
    // variable slots?
    //
    BlockSymbol* enclosing_block_symbol = enclosing_block -> block_symbol;
    // first such statement encountered in enclosing block?
    if (enclosing_block_symbol -> helper_variable_index < 0)
    {
        enclosing_block_symbol -> helper_variable_index =
            enclosing_block_symbol -> max_variable_index;
        enclosing_block_symbol -> max_variable_index += 2;
        if (ThisMethod() -> Type() != control.void_type)
        {
            if (control.IsDoubleWordType(ThisMethod() -> Type()))
                enclosing_block_symbol -> max_variable_index += 2;
            else enclosing_block_symbol -> max_variable_index += 1;
        }
    }

    //
    // Guess that the number of elements will not exceed the number of
    // statements + 3.
    //
    BlockSymbol* block = LocalSymbolTable().Top() ->
        InsertBlockSymbol(block_body -> NumStatements() + 3);
    block -> max_variable_index = enclosing_block_symbol -> max_variable_index;
    LocalSymbolTable().Push(block -> Table());

    block_body -> block_symbol = block;
    block_body -> nesting_level = LocalBlockStack().Size();
    LocalBlockStack().Push(block_body);

    ProcessBlockStatements(block_body);

    LocalBlockStack().Pop();
    LocalSymbolTable().Pop();

    if (LocalBlockStack().TopMaxEnclosedVariableIndex() <
        block -> max_variable_index)
    {
        LocalBlockStack().TopMaxEnclosedVariableIndex() =
            block -> max_variable_index;
    }

    synchronized_statement -> can_complete_normally =
        synchronized_statement -> block -> can_complete_normally;

    block -> CompressSpace(); // space optimization
}


void Semantic::CheckForAssignmentUsedAsTruthValue(Ast* expression)
{
    //
    // Warn about boolean assignments within if/while guards, i.e.
    // code such as "if (booleanLocal = booleanMethod())"
    // instead of "if (booleanLocal == booleanMethod())".
    //
    // We deliberately don't do anything like StripNops because
    // we want to allow the same compiler-quitening fix as gcc:
    // "if ((booleanLocal = booleanMethod()))".
    //
    AstAssignmentExpression* assignment_expression =
        expression -> AssignmentExpressionCast();
    if (assignment_expression &&
        assignment_expression -> SimpleAssignment() &&
        assignment_expression -> Type() == control.boolean_type)
    {
        ReportSemError(SemanticError::ASSIGNMENT_USED_AS_TRUTH_VALUE,
                       expression);
    }
}


void Semantic::ProcessIfStatement(Ast* stmt)
{
    AstIfStatement* if_statement = (AstIfStatement*) stmt;

    ProcessExpression(if_statement -> expression);

    TypeSymbol* cond_type = if_statement -> expression -> Type();
    if (cond_type != control.boolean_type && cond_type != control.no_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                       if_statement -> expression,
                       cond_type -> ContainingPackageName(),
                       cond_type -> ExternalName());
    }
    CheckForAssignmentUsedAsTruthValue(if_statement -> expression);

    //
    // Recall that the parser enclosed both true and false statements in
    // blocks, if necessary.
    //
    if_statement -> true_statement -> is_reachable =
        if_statement -> is_reachable;
    ProcessBlock(if_statement -> true_statement);

    if (if_statement -> false_statement_opt)
    {
        if_statement -> false_statement_opt -> is_reachable =
            if_statement -> is_reachable;
        ProcessBlock(if_statement -> false_statement_opt);

        if_statement -> can_complete_normally =
            if_statement -> true_statement -> can_complete_normally ||
            if_statement -> false_statement_opt -> can_complete_normally;
    }
    else if_statement -> can_complete_normally = if_statement -> is_reachable;
}


void Semantic::ProcessWhileStatement(Ast* stmt)
{
    AstWhileStatement* while_statement = (AstWhileStatement*) stmt;

    //
    // Recall that each while statement is enclosed in a unique block by the
    // parser, as is the loop body.
    //
    BreakableStatementStack().Push(LocalBlockStack().TopBlock());
    ContinuableStatementStack().Push(LocalBlockStack().TopBlock());

    AstBlock* enclosed_statement = while_statement -> statement;
    enclosed_statement -> is_reachable = while_statement -> is_reachable;

    ProcessExpression(while_statement -> expression);
    TypeSymbol* cond_type = while_statement -> expression -> Type();
    if (cond_type == control.boolean_type)
    {
        if (IsConstantFalse(while_statement -> expression))
        {
            if (while_statement -> is_reachable)
                while_statement -> can_complete_normally = true;
            enclosed_statement -> is_reachable = false;
        }
        else if (! IsConstantTrue(while_statement -> expression) &&
                 while_statement -> is_reachable)
        {
            while_statement -> can_complete_normally = true;
        }
    }
    else if (cond_type != control.no_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                       while_statement -> expression,
                       cond_type -> ContainingPackageName(),
                       cond_type -> ExternalName());
    }
    CheckForAssignmentUsedAsTruthValue(while_statement -> expression);

    ProcessBlock(enclosed_statement);

    if (! enclosed_statement -> is_reachable &&
        while_statement -> is_reachable)
    {
        ReportSemError(SemanticError::UNREACHABLE_STATEMENT,
                       enclosed_statement);
    }

    //
    // If the while statement contained a reachable break statement,
    // then the while statement can complete normally. It is marked
    // here only for completeness, as marking the enclosing block is
    // enough to propagate the proper information upward.
    //
    AstBlock* block_body = BreakableStatementStack().Top();
    if (block_body -> can_complete_normally)
        while_statement -> can_complete_normally = true;

    BreakableStatementStack().Pop();
    ContinuableStatementStack().Pop();
}


void Semantic::ProcessForStatement(Ast* stmt)
{
    AstForStatement* for_statement = (AstForStatement*) stmt;

    //
    // Note that in constructing the Ast, the parser encloses each
    // for-statement whose for-init-statements starts with a local
    // variable declaration in its own block. Therefore a redeclaration
    // of another local variable with the same name in a different loop
    // at the same nesting level will not cause any conflict.
    //
    // For example, the following sequence of statements is legal:
    //
    //     for (int i = 0; i < 10; i++);
    //     for (int i = 10; i < 20; i++);
    //
    for (unsigned i = 0; i < for_statement -> NumForInitStatements(); i++)
        ProcessStatement(for_statement -> ForInitStatement(i));

    //
    // Recall that each for statement is enclosed in a unique block by the
    // parser, as is the loop body.
    //
    BreakableStatementStack().Push(LocalBlockStack().TopBlock());
    ContinuableStatementStack().Push(LocalBlockStack().TopBlock());

    //
    // Assume that if the for_statement is reachable then its
    // contained statement is also reachable. If it turns out that the
    // condition (end) expression is a constant FALSE expression we will
    // change the assumption...
    //
    AstBlock* enclosed_statement = for_statement -> statement;
    enclosed_statement -> is_reachable = for_statement -> is_reachable;

    if (for_statement -> end_expression_opt)
    {
        ProcessExpression(for_statement -> end_expression_opt);
        TypeSymbol* cond_type = for_statement -> end_expression_opt -> Type();
        if (cond_type == control.boolean_type)
        {
            if (IsConstantFalse(for_statement -> end_expression_opt))
            {
                if (for_statement -> is_reachable)
                    for_statement -> can_complete_normally = true;
                enclosed_statement -> is_reachable = false;
            }
            else if (! IsConstantTrue(for_statement -> end_expression_opt) &&
                     for_statement -> is_reachable)
            {
                for_statement -> can_complete_normally = true;
            }
        }
        else if (cond_type != control.no_type)
        {
            ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                           for_statement -> end_expression_opt,
                           cond_type -> ContainingPackageName(),
                           cond_type -> ExternalName());
        }
    }

    ProcessBlock(enclosed_statement);

    if (! enclosed_statement -> is_reachable &&
        for_statement -> is_reachable)
    {
        ReportSemError(SemanticError::UNREACHABLE_STATEMENT,
                       enclosed_statement);
    }

    for (unsigned j = 0; j < for_statement -> NumForUpdateStatements(); j++)
        ProcessExpressionStatement(for_statement -> ForUpdateStatement(j));

    //
    // If the for statement contained a reachable break statement,
    // then the for statement can complete normally. It is marked
    // here only for completeness, as marking the enclosing block is
    // enough to propagate the proper information upward.
    //
    AstBlock* block_body = BreakableStatementStack().Top();
    if (block_body -> can_complete_normally)
        for_statement -> can_complete_normally = true;

    BreakableStatementStack().Pop();
    ContinuableStatementStack().Pop();
}


//
// Enhanced for loops (or foreach loops) were added in JDK 1.5, by JSR 201.
//
void Semantic::ProcessForeachStatement(Ast* stmt)
{
    AstForeachStatement* foreach = (AstForeachStatement*) stmt;

    //
    // Note that in constructing the Ast, the parser encloses each
    // for-statement whose for-init-statements starts with a local
    // variable declaration in its own block. Therefore a redeclaration
    // of another local variable with the same name in a different loop
    // at the same nesting level will not cause any conflict.
    //
    // For example, the following sequence of statements is legal:
    //
    //     for (int i : new int[0]);
    //     for (int i : new int[0]);
    //
    // Recall that each for statement is enclosed in a unique block by the
    // parser, as is the loop body.
    //
    AstBlock* enclosing_block = LocalBlockStack().TopBlock();
    BlockSymbol* enclosing_block_symbol = enclosing_block -> block_symbol;
    assert(enclosing_block_symbol -> helper_variable_index < 0);
    BreakableStatementStack().Push(enclosing_block);
    ContinuableStatementStack().Push(enclosing_block);

    //
    // The contained statement of a foreach is reachable iff the foreach is
    // reachable.
    //
    AstBlock* enclosed_statement = foreach -> statement;
    enclosed_statement -> is_reachable = foreach -> is_reachable;

    ProcessType(foreach -> formal_parameter -> type);
    assert(! foreach -> formal_parameter -> ellipsis_token_opt);
    TypeSymbol* index_type = foreach -> formal_parameter -> type -> symbol;
    AccessFlags access_flags =
        ProcessFormalModifiers(foreach -> formal_parameter);
    AstVariableDeclarator* variable_declarator =
        foreach -> formal_parameter -> formal_declarator;
    AstVariableDeclaratorId* name =
        variable_declarator -> variable_declarator_name;
    NameSymbol* name_symbol =
        lex_stream -> NameSymbol(name -> identifier_token);
    VariableSymbol* duplicate =
        LocalSymbolTable().FindVariableSymbol(name_symbol);
    if (duplicate)
    {
        ReportSemError(SemanticError::DUPLICATE_LOCAL_VARIABLE_DECLARATION,
                       name -> identifier_token, name_symbol -> Name(),
                       duplicate -> FileLoc());
    }
    else
    {
        WarnOfAccessibleFieldWithName(SemanticError::LOCAL_SHADOWS_FIELD,
                                      name, name_symbol, false);
        SymbolTable* table = LocalSymbolTable().Top();
        VariableSymbol* symbol = table -> InsertVariableSymbol(name_symbol);
        variable_declarator -> symbol = symbol;
        unsigned dims = index_type -> num_dimensions + name -> NumBrackets();
        symbol -> SetType(index_type -> GetArrayType(this, dims));
        symbol -> SetFlags(access_flags);
        symbol -> SetOwner(ThisMethod());
        symbol -> declarator = variable_declarator;
        symbol -> SetLocation();
        symbol -> SetLocalVariableIndex(enclosing_block_symbol ->
                                        max_variable_index++);
        if (control.IsDoubleWordType(symbol -> Type()))
            enclosing_block_symbol -> max_variable_index++;

        //
        // Warn against unconventional names. Note that there's no
        // strong convention for final local variables, so we allow
        // both the usual style for local variables and the usual
        // style for constant fields. We recommend the local variable
        // style, somewhat arbitrarily.
        //
        if (! symbol -> ACC_FINAL() && name_symbol -> IsBadStyleForVariable())
        {
            ReportSemError(SemanticError::UNCONVENTIONAL_VARIABLE_NAME,
                           name -> identifier_token, name_symbol -> Name());
        }
        else if (symbol -> ACC_FINAL() &&
                 name_symbol -> IsBadStyleForVariable() &&
                 name_symbol -> IsBadStyleForConstantField())
        {
            ReportSemError(SemanticError::UNCONVENTIONAL_VARIABLE_NAME,
                           name -> identifier_token, name_symbol -> Name());
        }
    }

    ProcessExpression(foreach -> expression);
    TypeSymbol* cond_type = foreach -> expression -> Type();
    TypeSymbol* component_type;
    if (control.option.source < JikesOption::SDK1_5)
    {
        ReportSemError(SemanticError::FOREACH_UNSUPPORTED,
                       stmt -> RightToken(),
                       foreach -> statement -> LeftToken() - 1);
    }
    else if (cond_type -> IsArray())
    {
        component_type = cond_type -> ArraySubtype();
        if (! CanAssignmentConvertReference(index_type, component_type))
        {
            ReportSemError(SemanticError::INCOMPATIBLE_TYPE_FOR_FOREACH,
                           foreach -> expression,
                           component_type -> ContainingPackageName(),
                           component_type -> ExternalName(),
                           index_type -> ContainingPackageName(),
                           index_type -> ExternalName());
        }
        // Need local variabls to stash array, array.length, and counter.
        enclosing_block_symbol -> helper_variable_index =
            enclosing_block_symbol -> max_variable_index;
        enclosing_block_symbol -> max_variable_index += 3;
    }
    else if (cond_type -> IsSubtype(control.Iterable()))
    {
        // FIXME: Support generics. Until then, we blindly accept all types,
        // and cause a ClassCastException if the user was wrong (this is not
        // semantically correct, but it allows testing).
        component_type = control.Object();
        if (! CanAssignmentConvertReference(index_type, component_type))
        {
            // HACK. Only complain about primitives, until generics are
            // fully supported and we can see if cond_type is parameterized,
            // and until autounboxing is implemented.
            if (index_type -> Primitive())
            ReportSemError(SemanticError::INCOMPATIBLE_TYPE_FOR_FOREACH,
                           foreach -> expression,
                           component_type -> ContainingPackageName(),
                           component_type -> ExternalName(),
                           index_type -> ContainingPackageName(),
                           index_type -> ExternalName());
            
        }
        // Need synthetic local variable to stash iterator.
        enclosing_block_symbol -> helper_variable_index =
            enclosing_block_symbol -> max_variable_index;
        enclosing_block_symbol -> max_variable_index++;
    }
    else if (cond_type != control.no_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_ITERABLE, foreach -> expression,
                       cond_type -> ContainingPackageName(),
                       cond_type -> ExternalName());
    }
    ProcessBlock(enclosed_statement);

    //
    // Foreach statements can always complete normally, if reachable, because
    // the array/iterator length could be 0.
    //
    foreach -> can_complete_normally = foreach -> is_reachable;
    BreakableStatementStack().Pop();
    ContinuableStatementStack().Pop();
}


void Semantic::ProcessSwitchStatement(Ast* stmt)
{
    AstSwitchStatement* switch_statement = (AstSwitchStatement*) stmt;

    AstBlock* enclosing_block = LocalBlockStack().TopBlock();

    //
    // We estimate a size for the switch symbol table based on the number of
    // lines in it. In a switch statement, local variable declarations have
    // scope over the entire main_block, but local classes only have scope in
    // the current switch block statement.
    //
    AstBlock* block_body = switch_statement -> switch_block;
    BlockSymbol* main_block = LocalSymbolTable().Top() -> InsertBlockSymbol();
    main_block -> max_variable_index =
        enclosing_block -> block_symbol -> max_variable_index;
    LocalSymbolTable().Push(main_block -> Table());

    block_body -> block_symbol = main_block;
    block_body -> nesting_level = LocalBlockStack().Size();
    LocalBlockStack().Push(block_body);
    BreakableStatementStack().Push(block_body);

    ProcessExpression(switch_statement -> expression);
    TypeSymbol* type = switch_statement -> expression -> Type();

    if (! control.IsSimpleIntegerValueType(type) && type != control.no_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_INTEGER,
                       switch_statement -> expression,
                       type -> ContainingPackageName(),
                       type -> ExternalName());
        type = control.no_type;
    }

    //
    // Count the number of case labels in this switch statement.
    //
    unsigned num_case_labels = 0;
    for (unsigned i = 0; i < block_body -> NumStatements(); i++)
        num_case_labels += switch_statement -> Block(i) -> NumSwitchLabels();
    switch_statement -> AllocateCases(num_case_labels);

    //
    // A switch block is reachable iff its switch statement is reachable.
    //
    block_body -> is_reachable = switch_statement -> is_reachable;
    for (unsigned j = 0; j < block_body -> NumStatements(); j++)
    {
        AstSwitchBlockStatement* switch_block_statement =
            switch_statement -> Block(j);
        for (unsigned k = 0;
             k < switch_block_statement -> NumSwitchLabels(); k++)
        {
            AstSwitchLabel* switch_label =
                switch_block_statement -> SwitchLabel(k);
            if (switch_label -> expression_opt)
            {
                ProcessExpression(switch_label -> expression_opt);
                TypeSymbol* case_type =
                    switch_label -> expression_opt -> Type();
                if (case_type == control.no_type)
                    continue;
                if (! control.IsSimpleIntegerValueType(case_type))
                {
                    ReportSemError(SemanticError::TYPE_NOT_INTEGER,
                                   switch_label -> expression_opt,
                                   case_type -> ContainingPackageName(),
                                   case_type -> ExternalName());
                    switch_label -> expression_opt -> symbol = control.no_type;
                }
                else if (! switch_label -> expression_opt -> IsConstant())
                {
                    ReportSemError(SemanticError::EXPRESSION_NOT_CONSTANT,
                                   switch_label -> expression_opt);
                    switch_label -> expression_opt -> symbol = control.no_type;
                }
                else if (CanAssignmentConvert(type,
                                              switch_label -> expression_opt))
                {
                    switch_label -> expression_opt =
                        ConvertToType(switch_label -> expression_opt, type);
                    CaseElement* case_element =
                        compilation_unit -> ast_pool -> GenCaseElement(j, k);
                    switch_statement -> AddCase(case_element);
                    case_element -> value = DYNAMIC_CAST<IntLiteralValue*>
                        (switch_label -> expression_opt -> value) -> value;
                }
                else
                {
                    IntToWstring value(DYNAMIC_CAST<IntLiteralValue*>
                                       (switch_label -> expression_opt ->
                                        value) -> value);
                    ReportSemError(SemanticError::VALUE_NOT_REPRESENTABLE_IN_SWITCH_TYPE,
                                   switch_label -> expression_opt,
                                   value.String(),
                                   type -> Name());
                }
            }
            else if (! switch_statement -> DefaultCase())
            {
                switch_statement -> DefaultCase() =
                    compilation_unit -> ast_pool -> GenCaseElement(j, k);
                switch_label -> map_index = num_case_labels - 1;
            }
            else
            {
                ReportSemError(SemanticError::MULTIPLE_DEFAULT_LABEL,
                               switch_block_statement -> SwitchLabel(k));
            }
        }

        //
        // The parser ensures that a switch block statement always has one
        // statement. When a switch block ends with a sequence of switch
        // labels that are not followed by any executable statements, an
        // artificial "empty" statement is added by the parser. Another
        // BlockSymbol level is used here for the scope of local classes,
        // but we share the BlockStack level to make break work correctly.
        //
        assert(switch_block_statement -> NumStatements() > 0);
        BlockSymbol* statement_block =
            LocalSymbolTable().Top() -> InsertBlockSymbol();
        statement_block -> max_variable_index =
            main_block -> max_variable_index;
        LocalSymbolTable().Push(statement_block -> Table());

        switch_block_statement -> block_symbol = statement_block;
        switch_block_statement -> nesting_level = LocalBlockStack().Size();
        LocalBlockStack().Push(block_body);
        switch_block_statement -> is_reachable =
            switch_statement -> is_reachable;
        ProcessBlockStatements(switch_block_statement);
        if (switch_block_statement -> can_complete_normally &&
            j != block_body -> NumStatements() - 1)
        {
            //
            // TODO: Improve the parser to allow this warning to be locally
            // disabled by adding a comment similar to "// fallthrough".
            //
            ReportSemError(SemanticError::SWITCH_FALLTHROUGH,
                           switch_block_statement);
        }

        if (statement_block -> max_variable_index <
            LocalBlockStack().TopMaxEnclosedVariableIndex())
        {
            statement_block -> max_variable_index =
                LocalBlockStack().TopMaxEnclosedVariableIndex();
        }
        LocalBlockStack().Pop();
        LocalSymbolTable().Pop();
        if (LocalBlockStack().TopMaxEnclosedVariableIndex() <
            statement_block -> max_variable_index)
        {
            LocalBlockStack().TopMaxEnclosedVariableIndex() =
                statement_block -> max_variable_index;
        }
        statement_block -> CompressSpace();
    }

    //
    // A switch statement can complete normally iff at least one of the
    // following is true:
    //
    // . The last statement in the switch block can complete normally.
    // . The switch block is empty or contains only switch labels.
    // . There is at least one switch label after the last switch block
    //   statement group.
    // . The switch block does not contain a default label.
    // . There is a reachable break statement that exits the switch
    //   statement. (See ProcessBreakStatement)
    //
    if (block_body -> can_complete_normally ||
        ! switch_statement -> DefaultCase())
    {
        switch_statement -> can_complete_normally = true;
    }
    else
    {
        AstSwitchBlockStatement* last_switch_block_statement =
            switch_statement -> Block(block_body -> NumStatements() - 1);

        assert(last_switch_block_statement -> NumStatements() > 0);

        AstStatement* last_statement = last_switch_block_statement ->
            Statement(last_switch_block_statement -> NumStatements() - 1);
        if (last_statement -> can_complete_normally)
            switch_statement -> can_complete_normally = true;
    }

    //
    // Iterate over the sorted cases, checking for duplicates, and setting
    // the map_index field of each AstCaseLabel (1-based, in order to leave
    // room for the default label).
    //
    if (switch_statement -> NumCases())
    {
        switch_statement -> SortCases();
        CaseElement* first_case = switch_statement -> Case(0);
        switch_statement -> Block(first_case -> block_index) ->
            SwitchLabel(first_case -> case_index) -> map_index = 0;
    }
    for (unsigned k = 1; k < switch_statement -> NumCases(); k++)
    {
        CaseElement* case_elt = switch_statement -> Case(k);
        switch_statement -> Block(case_elt -> block_index) ->
            SwitchLabel(case_elt -> case_index) -> map_index = k;
        if (case_elt -> value == switch_statement -> Case(k - 1) -> value)
        {
            IntToWstring value(case_elt -> value);
            ReportSemError(SemanticError::DUPLICATE_CASE_VALUE,
                           (switch_statement ->
                            Block(case_elt -> block_index) ->
                            SwitchLabel(case_elt -> case_index) ->
                            expression_opt),
                           value.String());
        }
    }

    //
    // If an enclosed block has a higher max_variable_index than the current
    // block, update max_variable_index in the current_block, accordingly.
    // Also, update the information for the block that immediately encloses
    // the current block.
    //
    if (main_block -> max_variable_index <
        LocalBlockStack().TopMaxEnclosedVariableIndex())
    {
        main_block -> max_variable_index =
            LocalBlockStack().TopMaxEnclosedVariableIndex();
    }

    BreakableStatementStack().Pop();
    LocalBlockStack().Pop();
    LocalSymbolTable().Pop();

    if (enclosing_block && (LocalBlockStack().TopMaxEnclosedVariableIndex() <
                            main_block -> max_variable_index))
    {
        LocalBlockStack().TopMaxEnclosedVariableIndex() =
            main_block -> max_variable_index;
    }

    main_block -> CompressSpace(); // space optimization
}


void Semantic::ProcessDoStatement(Ast* stmt)
{
    AstDoStatement* do_statement = (AstDoStatement*) stmt;

    //
    // Recall that each Do statement is enclosed in a unique block by the
    // parser, as is the loop body.
    //
    BreakableStatementStack().Push(LocalBlockStack().TopBlock());
    ContinuableStatementStack().Push(LocalBlockStack().TopBlock());

    AstBlock* enclosed_statement = do_statement -> statement;
    enclosed_statement -> is_reachable = do_statement -> is_reachable;

    ProcessBlock(enclosed_statement);

    ProcessExpression(do_statement -> expression);

    TypeSymbol* type = do_statement -> expression -> Type();
    if (type != control.boolean_type && type != control.no_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                       do_statement -> expression,
                       type -> ContainingPackageName(),
                       type -> ExternalName());
    }
    CheckForAssignmentUsedAsTruthValue(do_statement -> expression);

    //
    // A do statement can complete normally, iff at least one of the following
    // is true:
    //     1. The contained statement can complete normally and the condition
    //        expression is not a constant expression with the value true
    //     2. There is a reachable break statement that exits the do statement
    //        (This condition is true if the block that immediately encloses
    //        this do statement can complete normally. See
    //        ProcessBreakStatement)
    //
    AstBlock* block_body = (AstBlock*) BreakableStatementStack().Top();
    do_statement -> can_complete_normally =
        ((enclosed_statement -> can_complete_normally &&
          ! IsConstantTrue(do_statement -> expression)) ||
         block_body -> can_complete_normally);

    BreakableStatementStack().Pop();
    ContinuableStatementStack().Pop();
}


void Semantic::ProcessBreakStatement(Ast* stmt)
{
    AstBreakStatement* break_statement = (AstBreakStatement*) stmt;

    //
    // Recall that it is possible to break out of any labeled statement even
    // if it is not a do, for, while or switch statement.
    //
    if (break_statement -> identifier_token_opt)
    {
        NameSymbol* name_symbol =
            lex_stream -> NameSymbol(break_statement -> identifier_token_opt);
        LabelSymbol* label_symbol =
            LocalSymbolTable().FindLabelSymbol(name_symbol);

        if (label_symbol)
        {
            break_statement -> nesting_level = label_symbol -> nesting_level;
            AstBlock* block_body = label_symbol -> block;
            //
            // A labeled statement can complete normally if there is a
            // reachable break statement that exits the labeled statement.
            // If the break occurs in a try or catch block with a finally
            // block that completes abruptly, the break is discarded.
            //
            if (block_body && break_statement -> is_reachable &&
                AbruptFinallyStack().Top() < block_body -> nesting_level)
            {
                block_body -> can_complete_normally = true;
            }
        }
        else
        {
            AstBlock* block_body = (AstBlock*) LocalBlockStack().TopBlock();
            break_statement -> nesting_level = block_body -> nesting_level;
            ReportSemError(SemanticError::UNDECLARED_LABEL,
                           break_statement -> identifier_token_opt,
                           lex_stream -> NameString(break_statement ->
                                                    identifier_token_opt));
        }
    }
    else
    {
        AstBlock* block_body =
            (AstBlock*) (BreakableStatementStack().Size() > 0
                          ? BreakableStatementStack().Top()
                          : LocalBlockStack().TopBlock());
        break_statement -> nesting_level = block_body -> nesting_level;
        if (BreakableStatementStack().Size() > 0)
        {
            if (break_statement -> is_reachable &&
                AbruptFinallyStack().Top() < block_body -> nesting_level)
            {
                block_body -> can_complete_normally = true;
            }
        }
        else ReportSemError(SemanticError::MISPLACED_BREAK_STATEMENT,
                            break_statement);
    }
}


void Semantic::ProcessContinueStatement(Ast* stmt)
{
    AstContinueStatement* continue_statement = (AstContinueStatement*) stmt;

    //
    // The loop statement that is to be continued.
    //
    Ast* loop_statement = NULL;

    if (ContinuableStatementStack().Size() <= 0)
    {
        ReportSemError(SemanticError::MISPLACED_CONTINUE_STATEMENT,
                       continue_statement);
    }
    else if (continue_statement -> identifier_token_opt)
    {
        NameSymbol* name_symbol = lex_stream ->
            NameSymbol(continue_statement -> identifier_token_opt);
        LabelSymbol* label_symbol =
            LocalSymbolTable().FindLabelSymbol(name_symbol);

        if (label_symbol)
        {
            continue_statement -> nesting_level =
                label_symbol -> nesting_level;

            assert(label_symbol -> block -> NumStatements() > 0);

            loop_statement = label_symbol -> block -> Statement(0);
        }
        else
        {
            AstBlock* block_body = (AstBlock*) LocalBlockStack().TopBlock();
            continue_statement -> nesting_level = block_body -> nesting_level;
            ReportSemError(SemanticError::UNDECLARED_LABEL,
                           continue_statement -> identifier_token_opt,
                           lex_stream -> NameString(continue_statement ->
                                                    identifier_token_opt));
        }
    }
    else
    {
        AstBlock* block_body = (AstBlock*) ContinuableStatementStack().Top();
        loop_statement = block_body -> Statement(0);
        continue_statement -> nesting_level = block_body -> nesting_level;
    }

    //
    // If this is a valid continue statement, it is associated with a loop
    // statement. The parser created a block, if necessary, so that the loop
    // body is always a block, and we mark it as "can complete normally".
    // However, if the continue occurs in a try or catch block with a
    // corresponding abrupt finally clause, the continue is discarded.
    //
    if (loop_statement)
    {
        AstDoStatement* do_statement = loop_statement -> DoStatementCast();
        AstForStatement* for_statement = loop_statement -> ForStatementCast();
        AstWhileStatement* while_statement =
            loop_statement -> WhileStatementCast();
        AstForeachStatement* foreach_statement =
            loop_statement -> ForeachStatementCast();

        AstBlock* enclosed_statement = (do_statement
                                        ? do_statement -> statement
                                        : for_statement
                                        ? for_statement -> statement
                                        : while_statement
                                        ? while_statement -> statement
                                        : foreach_statement
                                        ? foreach_statement -> statement
                                        : (AstBlock*) NULL);
        if (enclosed_statement)
        {
            if (AbruptFinallyStack().Top() <
                continue_statement -> nesting_level)
            {
                enclosed_statement -> can_complete_normally = true;
            }
        }
        else
        {
            assert(continue_statement -> identifier_token_opt);

            ReportSemError(SemanticError::INVALID_CONTINUE_TARGET,
                           continue_statement,
                           lex_stream -> NameString(continue_statement ->
                                                    identifier_token_opt));
        }
    }
}


void Semantic::ProcessReturnStatement(Ast* stmt)
{
    AstReturnStatement* return_statement = (AstReturnStatement*) stmt;
    MethodSymbol* this_method = ThisMethod();

    if (this_method -> name_symbol == control.clinit_name_symbol ||
        this_method -> name_symbol == control.block_init_name_symbol)
    {
        ReportSemError(SemanticError::RETURN_STATEMENT_IN_INITIALIZER,
                       return_statement);
    }
    else if (return_statement -> expression_opt)
    {
        AstExpression* expression = return_statement -> expression_opt;
        ProcessExpressionOrStringConstant(expression);
        TypeSymbol* method_type = this_method -> Type();
        TypeSymbol* expression_type = expression -> Type();

        if (method_type == control.void_type ||
            this_method -> name_symbol == control.init_name_symbol)
        {
            ReportSemError(SemanticError::MISPLACED_RETURN_WITH_EXPRESSION,
                           return_statement);
        }
        else if (expression_type == control.null_type &&
                 method_type -> IsArray())
        {
            ReportSemError(SemanticError::EJ_RETURN_OF_NULL_ARRAY,
                           return_statement);
        }
        else if (expression_type != control.no_type)
        {
            if (method_type != expression_type)
            {
                if (CanAssignmentConvert(method_type, expression))
                    return_statement -> expression_opt =
                        ConvertToType(expression, method_type);
                else
                {
                    ReportSemError(SemanticError::MISMATCHED_RETURN_AND_METHOD_TYPE,
                                   expression,
                                   expression_type -> ContainingPackageName(),
                                   expression_type -> ExternalName(),
                                   method_type -> ContainingPackageName(),
                                   method_type -> ExternalName());
                }
            }
        }
    }
    else if (this_method -> Type() != control.void_type &&
             this_method -> name_symbol != control.init_name_symbol)
    {
        ReportSemError(SemanticError::MISPLACED_RETURN_WITH_NO_EXPRESSION,
                       return_statement);
    }
}


//
// Any exception that is neither RuntimeException or one of its subclasses
// nor Error or one of its subclasses is a checked exception. This also
// ignores invalid types. Additionally, 'throw null' results in a
// NullPointerException, so it is unchecked.
//
bool Semantic::CheckedException(TypeSymbol* exception)
{
    return (exception != control.null_type &&
            exception != control.no_type &&
            ! exception -> IsSubclass(control.RuntimeException()) &&
            ! exception -> IsSubclass(control.Error()));
}


bool Semantic::UncaughtException(TypeSymbol* exception)
{
    //
    // An unchecked exception or a bad type is ok !!
    //
    if (! CheckedException(exception))
        return false;

    //
    // Firstly, check the stack of try statements to see if the exception in
    // question is catchable.
    //
    for (int i = TryStatementStack().Size() - 1; i >= 0; i--)
    {
        AstTryStatement* try_statement = TryStatementStack()[i];

        //
        // If a try statement contains a finally clause that can't complete
        // normally then the exception is discarded, hence it is considered
        // catchable. See Spec 11.3.
        //
        if (try_statement -> finally_clause_opt &&
            (! try_statement -> finally_clause_opt -> block ->
             can_complete_normally))
        {
            return false;
        }

        //
        // Check each catch clause in turn if we are in the try block.
        //
        if (try_statement -> processing_try_block)
            for (unsigned k = 0; k < try_statement -> NumCatchClauses(); k++)
            {
                AstCatchClause* clause = try_statement -> CatchClause(k);
                VariableSymbol* symbol = clause -> parameter_symbol;
                if (CanAssignmentConvertReference(symbol -> Type(), exception))
                    return false;
            }
    }

    //
    // Check if the current method declares this in the throws clause (note
    // that field initializers are not in a current method).
    //
    MethodSymbol* this_method = ThisMethod();
    if (this_method)
    {
        for (int l = this_method -> NumThrows() - 1; l >= 0; l--)
        {
            if (CanAssignmentConvertReference(this_method -> Throws(l),
                                              exception))
                return false;
        }
    }

    //
    // In the special case of instance field initializers, and instance
    // initializer blocks, check if all constructors declare the exception
    // in the throws clause.
    //
    if ((this_method &&
         this_method -> Identity() == control.block_init_name_symbol) ||
        (ThisVariable() && ! ThisVariable() -> ACC_STATIC()))
    {
        TypeSymbol* this_type = ThisType();
        MethodSymbol* ctor =
            this_type -> FindMethodSymbol(control.init_name_symbol);
        if (! this_type -> Anonymous())
        {
            for ( ; ctor; ctor = ctor -> next_method)
            {
                int k;
                for (k = ctor -> NumThrows() - 1; k >= 0; k--)
                {
                    if (CanAssignmentConvertReference(ctor -> Throws(k),
                                                      exception))
                        break;
                }
                if (k < 0) // No hit was found in constructor.
                    break;
            }
            return ctor != NULL; // Did all constructors catch exception?
        }
        else
        {
            assert(ctor);
            int k = 0;
            for (k = ctor -> NumThrows() - 1; k >= 0; k--)
            {
                if (CanAssignmentConvertReference(ctor -> Throws(k),
                                                  exception))
                    break;
            }
            //
            // Anonymous classes must generate the constructor to handle all
            // possible initialization exceptions; this is possible because
            // a class instance can only be created at one point, so the
            // exception can be caught in the enclosing class. If we don't
            // find the exception, we must add it.
            //
            if (k < 0)
                ctor -> AddThrows(exception);
            return false;
        }
    }

    return true; // Nothing can catch the exception.
}


const wchar_t* Semantic::UncaughtExceptionContext()
{
    ErrorString s;
    MethodSymbol* this_method = ThisMethod();
    if (this_method)
    {
        s << " must be enclosed in a try statement that catches the "
          << "exception, ";
        if (this_method -> Identity() == control.clinit_name_symbol)
        {
            s << "since static initializers cannot throw checked exceptions.";
        }
        else
        {
            if (this_method -> Identity() == control.block_init_name_symbol)
            {
                assert(! ThisType() -> Anonymous());
                s << "or else every constructor in this class";
            }
            else if (this_method -> Identity() == control.init_name_symbol)
                s << "or else this constructor";
            else s << "or else this method";
            s << " must be declared to throw the exception.";
        }
    }
    else if (ThisType() -> ACC_INTERFACE())
    {
        s << " must be wrapped in a helper class method which catches the "
          << "exception, since interface field initializers cannot throw "
          << "checked exceptions.";
    }
    else
    {
        VariableSymbol* this_variable = ThisVariable();
        assert(this_variable);
        if (this_variable -> ACC_STATIC())
            s << " must be moved to a static initializer and enclosed in a "
              << "try statement which catches the exception, since static "
              << "initializers cannot throw checked exceptions.";
        else
        {
            assert(! ThisType() -> Anonymous());
            s << " must be moved to an instance initializer or constructor "
              << "and enclosed in a try statement which catches the "
              << "exception, or else every constructor in this class must be "
              << "declared to throw the exception.";
        }
    }
    return s.Array();
}


void Semantic::ProcessThrowStatement(Ast* stmt)
{
    AstThrowStatement* throw_statement = (AstThrowStatement*) stmt;

    ProcessExpression(throw_statement -> expression);
    TypeSymbol* type = throw_statement -> expression -> Type();

    if (type != control.no_type &&
        ! CanAssignmentConvertReference(control.Throwable(), type))
    {
        ReportSemError(SemanticError::EXPRESSION_NOT_THROWABLE,
                       throw_statement);
    }

    //
    // Since 'throw null' always generates NullPointerException, we do not
    // add it to the exception set; otherwise checked exception catch blocks
    // would be reachable because null is assignable to them.
    //
    SymbolSet* exception_set = TryExceptionTableStack().Top();
    if (exception_set && type != control.null_type)
        exception_set -> AddElement(type);

    if (UncaughtException(type))
        ReportSemError(SemanticError::UNCAUGHT_THROWN_EXCEPTION,
                       throw_statement, type -> ContainingPackageName(),
                       type -> ExternalName(), UncaughtExceptionContext());
}


void Semantic::ProcessTryStatement(Ast* stmt)
{
    AstTryStatement* try_statement = (AstTryStatement*) stmt;

    //
    // A try_statement containing a finally clause requires some extra local
    // variables in its immediately enclosing block. The first holds an
    // uncaught exception from the try or catch block.  The second holds the
    // return address of the jsr.  And if the method has a return type, 1-2
    // more slots are needed to hold the return value in the case of an
    // abrupt exit from a try or catch block.
    //
    // Meanwhile, statements within try or catch blocks cannot share local
    // variables with the finally block, because of a potential VerifyError if
    // the finally overwrites a register holding a monitor of an enclosed
    // synchronized statement during an abrupt exit.
    //
    AstBlock* enclosing_block = LocalBlockStack().TopBlock();
    int max_variable_index =
        enclosing_block -> block_symbol -> max_variable_index;

    if (try_statement -> finally_clause_opt)
    {
        BlockSymbol* enclosing_block_symbol = enclosing_block -> block_symbol;
        if (enclosing_block_symbol -> helper_variable_index < 0)
        {
            // first such statement encountered in enclosing block?
            enclosing_block_symbol -> helper_variable_index =
                enclosing_block_symbol -> max_variable_index;
            enclosing_block_symbol -> max_variable_index += 2;
            if (ThisMethod() -> Type() != control.void_type)
            {
                if (control.IsDoubleWordType(ThisMethod() -> Type()))
                    enclosing_block_symbol -> max_variable_index += 2;
                else enclosing_block_symbol -> max_variable_index++;
            }
        }

        //
        // A finally block is processed in the environment of its immediate
        // enclosing block (as opposed to the environment of its associated
        // try block).
        //
        // Note that the finally block must be processed prior to the other
        // blocks in the try statement, because the computation of whether or
        // not an exception is catchable in a try statement depends on the
        // termination status of the associated finally block. See the
        // UncaughtException function. In addition, any variables used in
        // the finally block cannot be safely used in the other blocks.
        //
        AstBlock* block_body = try_statement -> finally_clause_opt -> block;
        block_body -> is_reachable = try_statement -> is_reachable;
        assert(! try_statement -> can_complete_normally);
        ProcessBlock(block_body);
        max_variable_index = block_body -> block_symbol -> max_variable_index;

        //
        // Warn about empty finally blocks.
        //
        if (block_body -> NumStatements() == 0)
        {
            ReportSemError(SemanticError::EJ_EMPTY_FINALLY_BLOCK, block_body);
        }
        
        //
        // If the finally ends abruptly, then it discards any throw generated
        // by the try or catch blocks.
        //
        if (! block_body -> can_complete_normally)
        {
            TryExceptionTableStack().Push(new SymbolSet());
            AbruptFinallyStack().Push(block_body -> nesting_level);
        }
    }

    //
    // Note that the catch clauses are processed first - prior to processing
    // the main block - so that we can have their parameters available when we
    // are processing the main block, in case that block contains a throw
    // statement. See ProcessThrowStatement for more information. But since
    // a catch clause may be interrupted by an abrupt finally clause, we go
    // ahead and push the try block on the stack now, then use the field
    // processing_try_block later to mark the difference.
    //
    // Also, recall that the body of the catch blocks must not be
    // processed within the environment of the associated try whose
    // exceptions they are supposed to catch but within the immediate enclosing
    // block (which may itself be a try block).
    //
    TryStatementStack().Push(try_statement);
    for (unsigned i = 0; i < try_statement -> NumCatchClauses(); i++)
    {
        AstCatchClause* clause = try_statement -> CatchClause(i);
        AstFormalParameter* parameter = clause -> formal_parameter;
        assert(! parameter -> ellipsis_token_opt);
        AstVariableDeclaratorId* name =
            parameter -> formal_declarator -> variable_declarator_name;

        ProcessType(parameter -> type);
        TypeSymbol* parm_type = parameter -> type -> symbol;
        if (name -> NumBrackets())
        {
            parm_type = parm_type ->
                GetArrayType(this, (parm_type -> num_dimensions +
                                    name -> NumBrackets()));
        }
        if (! parm_type -> IsSubclass(control.Throwable()) &&
            parm_type != control.no_type)
        {
            ReportSemError(SemanticError::TYPE_NOT_THROWABLE, parameter,
                           parm_type -> ContainingPackageName(),
                           parm_type -> ExternalName());
            parm_type = control.no_type;
        }

        NameSymbol* name_symbol =
            lex_stream -> NameSymbol(name -> identifier_token);
        VariableSymbol* duplicate =
            LocalSymbolTable().FindVariableSymbol(name_symbol);
        if (duplicate)
        {
            ReportSemError(SemanticError::DUPLICATE_LOCAL_VARIABLE_DECLARATION,
                           name -> identifier_token, name_symbol -> Name(),
                           duplicate -> FileLoc());
        }
        WarnOfAccessibleFieldWithName(SemanticError::LOCAL_SHADOWS_FIELD,
                                      name, name_symbol, false);

        AstBlock* block_body = clause -> block;
        
        //
        // Warn about empty catch blocks.
        //
        if (control.option.pedantic && block_body -> NumStatements() == 0)
            ReportSemError(SemanticError::EJ_EMPTY_CATCH_BLOCK, block_body);

        //
        // Guess that the number of elements in the table will not exceed the
        // number of statements + the clause parameter.
        //
        BlockSymbol* block = LocalSymbolTable().Top() ->
            InsertBlockSymbol(block_body -> NumStatements() + 1);
        block -> max_variable_index = max_variable_index;
        LocalSymbolTable().Push(block -> Table());

        AccessFlags access_flags = ProcessFormalModifiers(parameter);

        VariableSymbol* symbol =
            LocalSymbolTable().Top() -> InsertVariableSymbol(name_symbol);
        symbol -> SetFlags(access_flags);
        symbol -> SetType(parm_type);
        symbol -> SetOwner(ThisMethod());
        symbol -> SetLocalVariableIndex(block -> max_variable_index++);
        symbol -> MarkComplete();
        symbol -> declarator = parameter -> formal_declarator;
        symbol -> SetLocation();
        parameter -> formal_declarator -> symbol = symbol;
        clause -> parameter_symbol = symbol;

        //
        // Note that for the purpose of semantic checking we assume that
        // the body of the catch block is reachable. Whether or not the catch
        // statement can be executed at all is checked later.
        //
        block_body -> is_reachable = true;

        block_body -> block_symbol = block;
        block_body -> nesting_level = LocalBlockStack().Size();
        LocalBlockStack().Push(block_body);

        ProcessBlockStatements(block_body);

        LocalBlockStack().Pop();
        LocalSymbolTable().Pop();

        //
        // Update the information for the block that immediately encloses
        // the current block.
        //
        if (LocalBlockStack().TopMaxEnclosedVariableIndex() <
            block -> max_variable_index)
        {
            LocalBlockStack().TopMaxEnclosedVariableIndex() =
                block -> max_variable_index;
        }

        //
        // If a catch clause block can complete normally, we assume
        // that the try statement can complete normally. This may
        // prove to be false later if we find out that the finally
        // clause cannot complete normally...
        //
        if (block_body -> can_complete_normally)
            try_statement -> can_complete_normally = true;

        block -> CompressSpace(); // space optimization
    }

    //
    // Finally, process the main try block.
    //
    try_statement -> processing_try_block = true;
    SymbolSet* exception_set = new SymbolSet;
    TryExceptionTableStack().Push(exception_set);

    try_statement -> block -> is_reachable = try_statement -> is_reachable;
    AstBlock* block_body = try_statement -> block;
    //
    // Guess that the number of elements in the table will not exceed the
    // number of statements + 3. This padding allows extra variable
    // declarations in things like for-init, without expensive reallocation.
    //
    BlockSymbol* block = LocalSymbolTable().Top() ->
        InsertBlockSymbol(block_body -> NumStatements() + 3);
    block -> max_variable_index = max_variable_index;
    LocalSymbolTable().Push(block -> Table());

    block_body -> block_symbol = block;
    block_body -> nesting_level = LocalBlockStack().Size();
    LocalBlockStack().Push(block_body);

    ProcessBlockStatements(block_body);

    LocalBlockStack().Pop();
    LocalSymbolTable().Pop();

    //
    // Update the information for the block that immediately encloses the
    // current block.
    //
    if (LocalBlockStack().TopMaxEnclosedVariableIndex() <
        block -> max_variable_index)
    {
        LocalBlockStack().TopMaxEnclosedVariableIndex() =
            block -> max_variable_index;
    }

    block -> CompressSpace(); // space optimization

    if (try_statement -> block -> can_complete_normally)
        try_statement -> can_complete_normally = true;

    //
    // A catch block is reachable iff both of the following are true:
    //     . Some expression or throw statement in the try block is reachable
    //       and can throw an exception that is assignable to the parameter
    //       of the catch clause C. Note that every try block, including an
    //       empty one, is considered to throw unchecked exceptions.
    //     . There is no earlier catch block A in the try statement such that
    //       the type of C's parameter is the same as or a subclass of the
    //       type of A's parameter.
    //
    // Note that the use of the word assignable here is slightly misleading.
    // It does not mean assignable in the strict sense defined in section 5.2.
    // Using the strict definition of 5.2, the rule can be more accurately
    // stated as follows:
    //
    //    . Catchable Exception:
    //      Some expression or throw statement in the try block is reachable
    //      and can throw an exception S that is assignable to the parameter
    //      with type T (S is a subclass of T) of the catch clause C.
    //      In this case, when S is thrown it will definitely be caught by
    //      clause C.
    //
    //    . Convertible Exception:
    //      The type T of the parameter of the catch clause C is assignable to
    //      the type S (T is a subclass of S) of an exception that can be
    //      thrown by some expression or throw statement in the try block that
    //      is reachable. This rule captures the idea that at run time an
    //      object declared to be of type S can actually be an instance of an
    //      object of type T in which case it will be caught by clause C.
    //
    Tuple<TypeSymbol*> catchable_exceptions;
    Tuple<TypeSymbol*> convertible_exceptions;
    exception_set -> AddElement(control.Error());
    exception_set -> AddElement(control.RuntimeException());
    for (unsigned l = 0; l < try_statement -> NumCatchClauses(); l++)
    {
        AstCatchClause* clause = try_statement -> CatchClause(l);
        TypeSymbol* type = clause -> parameter_symbol -> Type();
        if (type == control.no_type)
            continue;
        unsigned initial_length = catchable_exceptions.Length() +
            convertible_exceptions.Length();

        for (TypeSymbol* exception =
                 (TypeSymbol*) exception_set -> FirstElement();
             exception;
             exception = (TypeSymbol*) exception_set -> NextElement())
        {
            assert(exception != control.null_type);
            if (CanAssignmentConvertReference(type, exception))
                catchable_exceptions.Next() = exception;
            else if (CanAssignmentConvertReference(exception, type))
                convertible_exceptions.Next() = exception;
        }

        //
        // No exception was found which can be caught by this clause.
        //
        if (catchable_exceptions.Length() + convertible_exceptions.Length() ==
            initial_length)
        {
            ReportSemError(SemanticError::UNREACHABLE_CATCH_CLAUSE,
                           clause -> formal_parameter,
                           type -> ContainingPackageName(),
                           type -> ExternalName());
        }
        else
        {
            //
            // Search to see if this clause duplicates a prior one.
            //
            AstCatchClause* previous_clause;
            unsigned k;
            for (k = 0; k < l; k++)
            {
                previous_clause = try_statement -> CatchClause(k);
                if (type -> IsSubclass(previous_clause -> parameter_symbol ->
                                       Type()))
                    break;
            }

            if (k < l)
            {
                FileLocation loc(lex_stream,
                                 (previous_clause -> formal_parameter ->
                                  RightToken()));
                TypeSymbol* prev_type =
                    previous_clause -> parameter_symbol -> Type();
                ReportSemError(SemanticError::BLOCKED_CATCH_CLAUSE,
                               clause -> formal_parameter,
                               type -> ContainingPackageName(),
                               type -> ExternalName(),
                               prev_type -> ContainingPackageName(),
                               prev_type -> ExternalName(),
                               loc.location);
            }
            else clause -> block -> is_reachable = true;
        }
    }

    try_statement -> processing_try_block = false;
    TryStatementStack().Pop();
    TryExceptionTableStack().Pop();
    if (TryExceptionTableStack().Top())
    {
        //
        // First, remove all the thrown exceptions that are definitely caught
        // by the enclosing try statement. Then, add the remaining ones to the
        // set that must be caught by the immediately enclosing try statement.
        //
        for (unsigned i = 0; i < catchable_exceptions.Length(); i++)
            exception_set -> RemoveElement(catchable_exceptions[i]);
        TryExceptionTableStack().Top() -> Union(*exception_set);
    }
    delete exception_set;

    //
    // A try statement cannot complete normally if it contains a finally
    // clause that cannot complete normally. But remember that a continue
    // statement may have already marked the try statement as completing
    // normally. Clean up from above.
    //
    if (try_statement -> finally_clause_opt &&
        ! try_statement -> finally_clause_opt -> block -> can_complete_normally)
    {
        try_statement -> can_complete_normally = false;
        delete TryExceptionTableStack().Top();
        TryExceptionTableStack().Pop();
        AbruptFinallyStack().Pop();
    }
}


void Semantic::ProcessAssertStatement(Ast* stmt)
{
    AstAssertStatement* assert_statement = (AstAssertStatement*) stmt;

    ProcessExpression(assert_statement -> condition);

    TypeSymbol* type = assert_statement -> condition -> Type();
    if (type != control.no_type && type != control.boolean_type)
    {
        ReportSemError(SemanticError::TYPE_NOT_BOOLEAN,
                       assert_statement -> condition,
                       type -> ContainingPackageName(),
                       type -> ExternalName());
    }
    //
    // If the condition is not constant true, store a reference to this class's
    // assert variable (creating it if necessary as a side-effect). However,
    // if we are not emitting asserts, we can skip this.
    //
    else if (! IsConstantTrue(assert_statement -> condition) &&
             ! control.option.noassert)
    {
        assert_statement -> assert_variable =
            ThisType() -> FindOrInsertAssertVariable();
    }

    if (assert_statement -> message_opt)
    {
        ProcessExpressionOrStringConstant(assert_statement -> message_opt);
        if (assert_statement -> message_opt -> Type() == control.void_type)
            ReportSemError(SemanticError::TYPE_IS_VOID,
                           assert_statement -> message_opt,
                           assert_statement -> message_opt -> Type() -> Name());
    }

    //
    // Asserts can complete normally iff reachable.
    //
    assert_statement -> can_complete_normally =
        assert_statement -> is_reachable;
}


void Semantic::ProcessEmptyStatement(Ast* stmt)
{
    AstEmptyStatement* empty_statement = (AstEmptyStatement*) stmt;

    //
    // An empty statement can complete normally iff it is reachable.
    //
    empty_statement -> can_complete_normally = empty_statement -> is_reachable;
}


TypeSymbol* Semantic::GetLocalType(AstDeclaredType* class_declaration)
{
    NameSymbol* name_symbol = lex_stream ->
        NameSymbol(class_declaration -> class_body -> identifier_token);
    TypeSymbol* type =
        LocalSymbolTable().Top() -> InsertTypeSymbol(name_symbol);

    TypeSymbol* this_type = ThisType();
    TypeSymbol* outermost_type = this_type -> outermost_type;
    if (! this_type -> local)
        this_type -> local = new SymbolSet;

    //
    // Anonymous and local classes can clash if we don't use both when
    // determining the id number of this class.
    //
    IntToWstring value(this_type -> NumLocalTypes() +
                       this_type -> NumAnonymousTypes() + 1);
    int length = this_type -> ExternalNameLength() + 1 + value.Length() +
        name_symbol -> NameLength(); // +1 for $
    wchar_t* external_name = new wchar_t[length + 1]; // +1 for '\0';
    wcscpy(external_name, this_type -> ExternalName());
    wcscat(external_name, (control.option.target < JikesOption::SDK1_5
                           ? StringConstant::US_DS : StringConstant::US_MI));
    wcscat(external_name, value.String());
    wcscat(external_name, name_symbol -> Name());

    type -> outermost_type = outermost_type;
    type -> SetExternalIdentity(control.FindOrInsertName(external_name,
                                                         length));
    this_type -> local -> AddElement(type);

    delete [] external_name;

    return type;
}


void Semantic::ProcessClassDeclaration(Ast* stmt)
{
    AstLocalClassStatement* class_statement = (AstLocalClassStatement*) stmt;
    AstDeclaredType* class_declaration = class_statement -> declaration;
    AstClassBody* class_body = class_declaration -> class_body;

    CheckNestedTypeDuplication(state_stack.Top(),
                               class_body -> identifier_token);

    TypeSymbol* inner_type = GetLocalType(class_declaration);
    inner_type -> outermost_type = ThisType() -> outermost_type;
    inner_type -> supertypes_closure = new SymbolSet;
    inner_type -> subtypes_closure = new SymbolSet;
    inner_type -> subtypes = new SymbolSet;
    inner_type -> semantic_environment =
        new SemanticEnvironment(this, inner_type, state_stack.Top());
    inner_type -> declaration = class_body;
    inner_type -> file_symbol = source_file_symbol;
    inner_type -> SetFlags(ProcessLocalClassModifiers(class_declaration));
    inner_type -> SetOwner(ThisMethod());
    //
    // Add 3 extra elements for padding. May need a default constructor and
    // other support elements.
    //
    inner_type -> SetSymbolTable(class_body -> NumClassBodyDeclarations() + 3);
    inner_type -> SetLocation();
    inner_type -> SetSignature(control);

    //
    // If a local class is not in a static region, it needs a place to store
    // the enclosing instance.
    //
    if (! StaticRegion())
        inner_type -> InsertThis0();

    // Save environment for processing bodies later.
    class_body -> semantic_environment = inner_type -> semantic_environment;
    CheckNestedMembers(inner_type, class_body);
    ProcessTypeHeaders(class_body);

    ProcessMembers(class_body);
    CompleteSymbolTable(class_body);
    ProcessExecutableBodies(class_body);
    UpdateLocalConstructors(inner_type);
}


void Semantic::ProcessThisCall(AstThisCall* this_call)
{
    TypeSymbol* this_type = ThisType();

    // Signal that we are about to process an explicit constructor invocation.
    ExplicitConstructorInvocation() = this_call;

    if (this_call -> type_arguments_opt)
    {
        ReportSemError(SemanticError::EXPLICIT_TYPE_ARGUMENTS_UNSUPPORTED,
                       this_call -> type_arguments_opt);
    }
    bool bad_argument = ProcessArguments(this_call -> arguments);
    if (! bad_argument)
    {
        MethodSymbol* constructor = FindConstructor(this_type, this_call,
                                                    this_call -> this_token,
                                                    this_call -> RightToken());
        if (constructor)
        {
            this_call -> symbol = constructor;
            MethodInvocationConversion(this_call -> arguments, constructor);
            for (unsigned i = 0; i < constructor -> NumThrows(); i++)
            {
                TypeSymbol* exception = constructor -> Throws(i);
                if (UncaughtException(exception))
                    ReportSemError(SemanticError::UNCAUGHT_EXPLICIT_THIS_EXCEPTION,
                                   this_call -> this_token,
                                   exception -> ContainingPackageName(),
                                   exception -> ExternalName());
            }

            //
            // Not all shadowed variables are known yet, but there is no
            // need to save context, since all shadow variables required by
            // the target constructor can just be passed along.
            //
        }
    }

    //
    // Signal that we are no longer processing an explicit constructor
    // invocation.
    //
    ExplicitConstructorInvocation() = NULL;
}


void Semantic::ProcessSuperCall(AstSuperCall* super_call)
{
    TypeSymbol* this_type = ThisType();
    if (super_call -> symbol)
    {
        assert(this_type -> Anonymous());
        return;
    }

    // Signal that we are about to process an explicit constructor invocation.
    ExplicitConstructorInvocation() = super_call;

    TypeSymbol* super_type = this_type -> super;
    if (! super_type)
    {
        assert(this_type == control.Object());
        ReportSemError(SemanticError::OBJECT_HAS_NO_SUPER_TYPE,
                       super_call -> super_token);
        return;
    }

    if (super_call -> base_opt)
    {
        ProcessExpression(super_call -> base_opt);

        TypeSymbol* expr_type = super_call -> base_opt -> Type();
        if (expr_type != control.no_type)
        {
            TypeSymbol* containing_type = super_type -> EnclosingType();
            if (expr_type -> Primitive() || expr_type == control.null_type)
            {
                ReportSemError(SemanticError::TYPE_NOT_REFERENCE,
                               super_call -> base_opt,
                               expr_type -> ExternalName());
                super_call -> base_opt -> symbol = control.no_type;
            }
            else if (! containing_type)
            {
                if (! super_type -> Bad())
                    ReportSemError(SemanticError::SUPER_TYPE_NOT_INNER_CLASS,
                                   super_call -> base_opt,
                                   super_type -> ContainingPackageName(),
                                   super_type -> ExternalName(),
                                   this_type -> ContainingPackageName(),
                                   this_type -> ExternalName(),
                                   expr_type -> ContainingPackageName(),
                                   expr_type -> ExternalName());
                super_call -> base_opt -> symbol = control.no_type;
            }
            //
            // JLS2 8.8.5.1: For an enclosing class O of the superclass,
            // the qualifying primary must be of type O or a subclass.
            //
            else if (! expr_type -> IsSubclass(containing_type))
            {
                ReportSemError(SemanticError::INVALID_ENCLOSING_INSTANCE,
                               super_call -> base_opt,
                               this_type -> ContainingPackageName(),
                               this_type -> ExternalName(),
                               containing_type -> ContainingPackageName(),
                               containing_type -> ExternalName(),
                               expr_type -> ContainingPackageName(),
                               expr_type -> ExternalName());
                super_call -> base_opt -> symbol = control.no_type;
            }
        }
    }
    else // (! super_call -> base_opt)
    {
        if (super_type && super_type -> EnclosingType())
            super_call -> base_opt =
                CreateAccessToType(super_call, super_type -> EnclosingType());
    }

    if (super_call -> type_arguments_opt)
    {
        ReportSemError(SemanticError::EXPLICIT_TYPE_ARGUMENTS_UNSUPPORTED,
                       super_call -> type_arguments_opt);
    }
    MethodSymbol* constructor = NULL;
    bool bad_argument = ProcessArguments(super_call -> arguments);
    if (! bad_argument)
    {
        constructor = FindConstructor(super_type, super_call,
                                      super_call -> super_token,
                                      super_call -> RightToken());
    }

    if (constructor)
    {
        if (constructor -> ACC_PRIVATE())
        {
            //
            // Create accessor constructor, and add extra null
            // to the constructor invocation.
            //
            constructor = super_type -> GetReadAccessConstructor(constructor);
            super_call -> arguments -> AddNullArgument();
        }

        super_call -> symbol = constructor;
        if (super_call -> base_opt)
        {
            assert(CanAssignmentConvertReference(super_type -> EnclosingType(),
                                                 super_call -> base_opt -> Type()));

            super_call -> base_opt =
                ConvertToType(super_call -> base_opt,
                              super_type -> EnclosingType());
        }
        MethodInvocationConversion(super_call -> arguments, constructor);

        //
        // Make sure that the throws signature of the constructor is
        // processed.
        //
        unsigned i;
        for (i = 0; i < constructor -> NumThrows(); i++)
        {
            TypeSymbol* exception = constructor -> Throws(i);
            if (UncaughtException(exception))
                ReportSemError(SemanticError::UNCAUGHT_EXPLICIT_SUPER_EXCEPTION,
                               super_call,
                               exception -> ContainingPackageName(),
                               exception -> ExternalName(),
                               constructor -> containing_type -> ContainingPackageName(),
                               constructor -> containing_type -> ExternalName());
        }

        //
        // A local super type may use enclosed local variables. If so, we
        // must add the parameters which allow the local type to
        // initialize its shadows.
        //
        if (super_type -> IsLocal())
        {
            unsigned param_count = super_type -> NumConstructorParameters();
            if (super_type -> LocalClassProcessingCompleted() && param_count)
            {
                super_call -> arguments -> AllocateLocalArguments(param_count);
                for (i = 0; i < param_count; i++)
                {
                    //
                    // We may need to create a shadow in the outermost
                    // local class enclosing the variable.
                    //
                    AstName* simple_name = compilation_unit ->
                        ast_pool -> GenName(super_call -> super_token);
                    VariableSymbol* accessor =
                        FindLocalVariable(super_type -> ConstructorParameter(i),
                                          this_type);
                    simple_name -> symbol = accessor;
                    TypeSymbol* owner = accessor -> ContainingType();
                    if (owner != this_type)
                        CreateAccessToScopedVariable(simple_name, owner);
                    super_call -> arguments -> AddLocalArgument(simple_name);
                }
            }
            else
            {
                //
                // We are within body of super_type; save processing for
                // later, since not all shadows may be known yet. See
                // ProcessClassDeclaration.
                //
                super_type -> AddLocalConstructorCallEnvironment
                    (GetEnvironment(super_call -> arguments));
            }
        }
    }

    //
    // Signal that we are no longer processing an explicit constructor
    // invocation.
    //
    ExplicitConstructorInvocation() = NULL;
}


//
// Checks that types in a throws clause extend Throwable. throws_list is NULL
// except in pedantic mode, where it is used to detect duplicates.
//
void Semantic::CheckThrow(AstTypeName* throw_expression,
                          Tuple<AstTypeName*>* throws_list)
{
    TypeSymbol* throw_type = throw_expression -> symbol;
    if (throw_type -> Bad())
        return;

    if (throw_type -> ACC_INTERFACE())
    {
        ReportSemError(SemanticError::NOT_A_CLASS, throw_expression,
                       throw_type -> ContainingPackageName(),
                       throw_type -> ExternalName());
    }
    else if (! throw_type -> IsSubclass(control.Throwable()))
    {
        ReportSemError(SemanticError::TYPE_NOT_THROWABLE, throw_expression,
                       throw_type -> ContainingPackageName(),
                       throw_type -> ExternalName());
    }
    else if (throw_type == control.Exception() ||
             throw_type == control.Throwable())
    {
        ReportSemError(SemanticError::EJ_OVERLY_GENERAL_THROWS_CLAUSE,
                       throw_expression);
    }
    else if (control.option.pedantic)
    {
        assert(throws_list);
        if (! CheckedException(throw_type))
            ReportSemError(SemanticError::UNCHECKED_THROWS_CLAUSE_CLASS,
                           throw_expression,
                           throw_type -> ContainingPackageName(),
                           throw_type -> ExternalName());
        else
        {
            bool add = true;
            for (unsigned i = 0; i < throws_list -> Length(); i++)
            {
                AstTypeName* other_expr = (*throws_list)[i];
                TypeSymbol* other_type = other_expr -> symbol;
                if (other_type == throw_type)
                {
                    ReportSemError(SemanticError::DUPLICATE_THROWS_CLAUSE_CLASS,
                                   throw_expression,
                                   throw_type -> ContainingPackageName(),
                                   throw_type -> ExternalName());
                    add = false;
                }
                else if (throw_type -> IsSubclass(other_type))
                {
                    ReportSemError(SemanticError::REDUNDANT_THROWS_CLAUSE_CLASS,
                                   throw_expression,
                                   throw_type -> ContainingPackageName(),
                                   throw_type -> ExternalName(),
                                   other_type -> ContainingPackageName(),
                                   other_type -> ExternalName());
                    add = false;
                }
                else if (other_type -> IsSubclass(throw_type))
                {
                    ReportSemError(SemanticError::REDUNDANT_THROWS_CLAUSE_CLASS,
                                   other_expr,
                                   other_type -> ContainingPackageName(),
                                   other_type -> ExternalName(),
                                   throw_type -> ContainingPackageName(),
                                   throw_type -> ExternalName());
                    //
                    // Remove other type from the list, to reduce extra errors.
                    //
                    int last_index = throws_list -> Length() - 1;
                    (*throws_list)[i] = (*throws_list)[last_index];
                    throws_list -> Reset(last_index);
                    i--;
                }
            }
            if (add)
                throws_list -> Next() = throw_expression;
        }
    }
}


void Semantic::ProcessMethodBody(AstMethodDeclaration* method_declaration)
{
    MethodSymbol* this_method = ThisMethod();

    if (method_declaration -> NumThrows())
    {
        Tuple<AstTypeName*>* throws_list = NULL;
        if (control.option.pedantic)
            throws_list = new Tuple<AstTypeName*>
                (method_declaration -> NumThrows());
        for (unsigned k = 0; k < method_declaration -> NumThrows(); k++)
            CheckThrow(method_declaration -> Throw(k), throws_list);
        delete throws_list;
    }

    if (method_declaration -> method_body_opt)
    {
        AstMethodBody* method_body = method_declaration -> method_body_opt;
        if (method_body -> explicit_constructor_opt)
            ReportSemError(SemanticError::MISPLACED_EXPLICIT_CONSTRUCTOR,
                           method_body -> explicit_constructor_opt);
        method_body -> block_symbol = this_method -> block_symbol;
        method_body -> nesting_level = LocalBlockStack().Size();
        LocalBlockStack().Push(method_body);

        ProcessBlockStatements(method_body);

        LocalBlockStack().Pop();

        if (method_body -> can_complete_normally)
        {
            if (this_method -> Type() == control.void_type)
            {
                AstReturnStatement* return_statement =
                    compilation_unit -> ast_pool -> GenReturnStatement();
                return_statement -> return_token =
                    method_body -> right_brace_token;
                return_statement -> semicolon_token =
                    method_body -> right_brace_token;
                return_statement -> is_reachable = true;
                method_body -> can_complete_normally = false;
                method_body -> AddStatement(return_statement);
            }
            else
            {
                ReportSemError(SemanticError::TYPED_METHOD_WITH_NO_RETURN,
                               method_declaration -> type -> LeftToken(),
                               method_declaration -> method_declarator -> identifier_token,
                               this_method -> Header(),
                               this_method -> Type() -> Name());
            }
        }

        if (this_method -> ACC_ABSTRACT() || this_method -> ACC_NATIVE())
        {
            ReportSemError(SemanticError::ABSTRACT_METHOD_WITH_BODY,
                           method_declaration, this_method -> Header());
        }
    }
    else if (! (this_method -> ACC_ABSTRACT() || this_method -> ACC_NATIVE()))
    {
        ReportSemError(SemanticError::NON_ABSTRACT_METHOD_WITHOUT_BODY,
                       method_declaration, this_method -> Header());
    }

    this_method -> block_symbol -> CompressSpace(); // space optimization
}


void Semantic::ProcessConstructorBody(AstConstructorDeclaration* constructor_declaration)
{
    TypeSymbol* this_type = ThisType();
    MethodSymbol* this_method = ThisMethod();

    if (constructor_declaration -> NumThrows())
    {
        Tuple<AstTypeName*>* throws_list = NULL;
        if (control.option.pedantic)
            throws_list = new Tuple<AstTypeName*>
                (constructor_declaration -> NumThrows());
        for (unsigned k = 0; k < constructor_declaration -> NumThrows(); k++)
            CheckThrow(constructor_declaration -> Throw(k), throws_list);
        delete throws_list;
    }

    AstMethodBody* constructor_block =
        constructor_declaration -> constructor_body;

    AstSuperCall* super_call = NULL;
    TypeSymbol* super_type = this_type -> super;

    if (constructor_block -> explicit_constructor_opt)
    {
        super_call =
            constructor_block -> explicit_constructor_opt -> SuperCallCast();
        if (super_call)
            ProcessSuperCall(super_call);
        else
        {
            AstThisCall* this_call = constructor_block ->
                explicit_constructor_opt -> ThisCallCast();
            assert(this_call);
            ProcessThisCall(this_call);
        }
    }
    else if (super_type)
    {
        TokenIndex loc = constructor_block -> LeftToken();
        super_call = compilation_unit -> ast_pool -> GenSuperCall();
        super_call -> super_token = loc;
        super_call -> arguments =
            compilation_unit -> ast_pool -> GenArguments(loc, loc);
        super_call -> semicolon_token = loc;

        constructor_block -> explicit_constructor_opt = super_call;

        ProcessSuperCall(super_call);
    }

    //
    // Guess that the number of elements will not exceed the number of
    // statements.
    //
    int table_size = constructor_block -> NumStatements();
    BlockSymbol* block = LocalSymbolTable().Top() ->
        InsertBlockSymbol(table_size);
    block -> max_variable_index =
        this_method -> block_symbol -> max_variable_index;
    LocalSymbolTable().Push(block -> Table());

    constructor_block -> block_symbol = block;
    constructor_block -> nesting_level = LocalBlockStack().Size();
    LocalBlockStack().Push(constructor_block);

    ProcessBlockStatements(constructor_block);

    if (constructor_block -> can_complete_normally)
    {
        AstReturnStatement* return_statement =
            compilation_unit -> ast_pool -> GenReturnStatement();
        return_statement -> return_token =
            constructor_block -> right_brace_token;
        return_statement -> semicolon_token =
            constructor_block -> right_brace_token;
        return_statement -> is_reachable = true;
        constructor_block -> can_complete_normally = false;
        constructor_block -> AddStatement(return_statement);
    }

    LocalBlockStack().Pop();
    LocalSymbolTable().Pop();

    //
    // Update the local variable info for the main block associated with this
    // constructor.
    //
    if (this_method -> block_symbol -> max_variable_index <
        block -> max_variable_index)
    {
        this_method -> block_symbol -> max_variable_index =
            block -> max_variable_index;
    }

    block -> CompressSpace(); // space optimization
}


void Semantic::ProcessExecutableBodies(AstClassBody* class_body)
{
    if (compilation_unit -> BadCompilationUnitCast())
        return; // errors were detected, exit now

    state_stack.Push(class_body -> semantic_environment);
    TypeSymbol* this_type = ThisType();
    unsigned i;

    assert(this_type -> HeaderProcessed());
    assert(this_type -> ConstructorMembersProcessed());
    assert(this_type -> MethodMembersProcessed());
    assert(this_type -> FieldMembersProcessed());

    // All variable declarations have already been processed.
    if (! this_type -> ACC_INTERFACE())
    {
        //
        // Compute the set of instance final variables which must be assigned
        // in every constructor.
        //
        Tuple<VariableSymbol*> unassigned(FinalFields() -> Length());
        for (i = 0; i < FinalFields() -> Length(); i++)
        {
            VariableSymbol* variable_symbol = (*FinalFields())[i];
            if (! DefinitelyAssignedVariables() -> da_set[i])
            {
                assert(! variable_symbol -> ACC_STATIC());
                unassigned.Next() = variable_symbol;
            }
        }
        if (class_body -> NumConstructors() == 0)
        {
            //
            // Issue an error for each unassigned final.
            //
            for (i = 0; i < unassigned.Length(); i++)
            {
                ReportSemError(SemanticError::UNINITIALIZED_FINAL_VARIABLE,
                               unassigned[i] -> declarator,
                               unassigned[i] -> Name());
            }
            //
            // Process the body of the default constructor, if there is one (if
            // the class is invalid, one might not exist).
            //
            if (class_body -> default_constructor)
            {
                ThisMethod() =
                    class_body -> default_constructor -> constructor_symbol;
                LocalSymbolTable().Push(ThisMethod() -> block_symbol ->
                                        Table());
                ProcessConstructorBody(class_body -> default_constructor);
                LocalSymbolTable().Pop();
                ThisMethod() -> max_block_depth = 1;
            }
        }
        else
        {
            DefinitePair initial_state(*DefinitelyAssignedVariables());
            for (i = 0; i < class_body -> NumConstructors(); i++)
            {
                AstConstructorDeclaration* constructor_decl =
                    class_body -> Constructor(i);
                MethodSymbol* this_method =
                    constructor_decl -> constructor_symbol;
                if (! this_method)
                    continue;
                ThisMethod() = this_method;
                AstMethodBody* constructor_block =
                    constructor_decl -> constructor_body;

                LocalSymbolTable().Push(this_method -> block_symbol ->
                                        Table());
                LocalBlockStack().max_size = 0;
                ProcessConstructorBody(constructor_decl);
                LocalSymbolTable().Pop();
                this_method -> max_block_depth = LocalBlockStack().max_size;
                //
                // Each constructor starts from the same initial definite
                // assignment status, except those which call this() start with
                // all fields definitely assigned.
                //
                if (constructor_block -> explicit_constructor_opt &&
                    (constructor_block -> explicit_constructor_opt ->
                     ThisCallCast()))
                {
                    DefinitelyAssignedVariables() -> AssignAll();
                    DefiniteConstructorBody(constructor_decl);
                }
                else
                {
                    *DefinitelyAssignedVariables() = initial_state;
                    DefiniteConstructorBody(constructor_decl);
                    for (unsigned k = 0; k < unassigned.Length(); k++)
                    {
                        VariableSymbol* variable_symbol = unassigned[k];
                        if (! DefinitelyAssignedVariables() ->
                            da_set[variable_symbol -> LocalVariableIndex()])
                        {
                            ReportSemError(SemanticError::UNINITIALIZED_FINAL_VARIABLE_IN_CONSTRUCTOR,
                                           constructor_decl,
                                           variable_symbol -> Name());
                        }
                    }
                }
            }
            ConstructorCycleChecker cycle_checker(class_body);
        }
    }

    //
    // No need to worry about private access constructors, as we have already
    // done all necessary processing when creating them. Following all
    // constructors, all fields are definitely assigned, and are no longer
    // treated as blank finals.
    //
    DefinitelyAssignedVariables() -> AssignAll();
    BlankFinals() -> SetEmpty();

    for (i = 0; i < class_body -> NumMethods(); i++)
    {
        AstMethodDeclaration* method_decl = class_body -> Method(i);
        ThisMethod() = method_decl -> method_symbol;
        MethodSymbol* this_method = ThisMethod();
        if (this_method)
        {
            LocalSymbolTable().Push(this_method -> block_symbol -> Table());
            LocalBlockStack().max_size = 0;
            unsigned start_num_errors = NumErrors();
            ProcessMethodBody(method_decl);
            LocalSymbolTable().Pop();
            this_method -> max_block_depth = LocalBlockStack().max_size;
            if (NumErrors() == start_num_errors)
                DefiniteMethodBody(method_decl);
        }
    }
    ThisMethod() = NULL;

    //
    // Recursively process all inner types.
    //
    for (i = 0; i < class_body -> NumNestedClasses(); i++)
    {
        AstClassDeclaration* declaration = class_body -> NestedClass(i);
        if (declaration -> class_body -> semantic_environment)
            ProcessExecutableBodies(declaration -> class_body);
    }
    for (i = 0; i < class_body -> NumNestedInterfaces(); i++)
    {
        AstInterfaceDeclaration* declaration =
            class_body -> NestedInterface(i);
        if (declaration -> class_body -> semantic_environment)
            ProcessExecutableBodies(declaration -> class_body);
    }

    DefiniteCleanUp();
    state_stack.Pop();
}


#ifdef HAVE_JIKES_NAMESPACE
} // Close namespace Jikes block
#endif

