private int endCheck()
    {
        switch(type)
        {
            case Token.BREAK:
                return endCheckBreak();

            case Token.EXPR_VOID:
                if (this.first != null)
                    return first.endCheck();
                return END_DROPS_OFF;

            case Token.YIELD:
                return END_YIELDS;

            case Token.CONTINUE:
            case Token.THROW:
                return END_UNREACHED;

            case Token.RETURN:
                if (this.first != null)
                    return END_RETURNS_VALUE;
                return END_RETURNS;

            case Token.TARGET:
                if (next != null)
                    return next.endCheck();
                return END_DROPS_OFF;

            case Token.LOOP:
                return endCheckLoop();

            case Token.LOCAL_BLOCK:
            case Token.BLOCK:
                // there are several special kinds of blocks
                if (first == null)
                    return END_DROPS_OFF;

                switch(first.type) {
                    case Token.LABEL:
                        return first.endCheckLabel();

                    case Token.IFNE:
                        return first.endCheckIf();

                    case Token.SWITCH:
                        return first.endCheckSwitch();

                    case Token.TRY:
                        return first.endCheckTry();

                    default:
                        return endCheckBlock();
                }

            default:
                return END_DROPS_OFF;
        }
    }
private int endCheck ( ) { switch ( type ) { case Token . BREAK : return endCheckBreak ( ) ; case Token . EXPR_VOID : if ( this . first != null ) return first . endCheck ( ) ; return END_DROPS_OFF ; case Token . YIELD : return END_YIELDS ; case Token . CONTINUE : case Token . THROW : return END_UNREACHED ; case Token . RETURN : if ( this . first != null ) return END_RETURNS_VALUE ; return END_RETURNS ; case Token . TARGET : if ( next != null ) return next . endCheck ( ) ; return END_DROPS_OFF ; case Token . LOOP : return endCheckLoop ( ) ; case Token . LOCAL_BLOCK : case Token . BLOCK : if ( first == null ) return END_DROPS_OFF ; switch ( first . type ) { case Token . LABEL : return first . endCheckLabel ( ) ; case Token . IFNE : return first . endCheckIf ( ) ; case Token . SWITCH : return first . endCheckSwitch ( ) ; case Token . TRY : return first . endCheckTry ( ) ; default : return endCheckBlock ( ) ; } default : return END_DROPS_OFF ; } }
endCheck() examines the body of a function, doing a basic reachability
analysis and returns a combination of flags END_* flags that indicate
how the function execution can terminate. These constitute only the
pessimistic set of termination conditions. It is possible that at
runtime certain code paths will never be actually taken. Hence this
analysis will flag errors in cases where there may not be errors.
@return logical OR of END_* flags