public Object visit(IfStatement node) {
            Expression condition = node.getCondition();
            Block thenPart = node.getThenPart();
            Block elsePart = node.getElsePart();
            Variable[] thenCasts = null;
            Variable[] elseCasts = null;

            int preCondErrorCount = mErrorCount;
            check(condition);

            // NOTE: there is no need to check the condition type or convert
            // to a boolean since the generator will use the truthful checker
            // to ensure the condition is met

            if (preCondErrorCount == mErrorCount) {
                IsaDetector detector = new IsaDetector();
                condition.accept(detector);
                thenCasts = detector.getThenCasts();
                elseCasts = detector.getElseCasts();
            }

            Scope thenScope = null;
            Scope elseScope = null;

            thenScope = enterScope();
            if (thenPart != null) {
                Statement stmt = createCasts
                    (thenScope, thenCasts, thenPart.getSourceInfo());
                // Don't typecheck any inserted casts, they are already correct
                check(thenPart);
                thenPart.setInitializer(stmt);
            }
            exitScope();

            elseScope = enterScope();
            if (elsePart != null) {
                Statement stmt = createCasts
                    (elseScope, elseCasts, elsePart.getSourceInfo());
                // Don't typecheck any inserted casts, they are already correct
                check(elsePart);
                elsePart.setInitializer(stmt);
            }
            exitScope();

            // Merge then and else scopes
            Variable[] vars = thenScope.intersect(elseScope);

            if (vars.length == 0) {
                node.setMergedVariables(vars);
            }
            else {
                if (mExceptionGuardian && condition.isExceptionPossible()) {
                    // If condition could throw an exception, then the
                    // exception handler needs to ensure that these variables
                    // are assigned null. Therefore, the variables need to be
                    // able to accept null.
                    for (int i=0; i<vars.length; i++) {
                        Variable v = vars[i];
                        Type t = v.getType();
                        if (t.isNonNull()) {
                            v = (Variable)v.clone();
                            v.setType(t.toNullable());
                            vars[i] = v;
                        }
                    }
                }

                node.setMergedVariables(vars);

                // Add corrective code as a result of merging.
                if (thenPart == null) {
                    thenPart = new Block(node.getSourceInfo());
                    node.setThenPart(thenPart);
                }
                Statement fin = createConversions
                    (thenScope, vars, thenPart.getSourceInfo());
                thenPart.setFinalizer(fin);

                if (elsePart == null) {
                    elsePart = new Block(node.getSourceInfo());
                    node.setElsePart(elsePart);
                }
                fin = createConversions
                    (elseScope, vars, elsePart.getSourceInfo());
                elsePart.setFinalizer(fin);

                // Re-declare all new variables with new types for future
                // variable references.
                mScope.declareVariables(vars);
            }

            return null;
        }