This replaces r2963.  It adds a very narrow static eval rule for
JavaScript nodes: literal == null can be replaced by true or false
depending on what the literal is.

Review by: scottb (desk check)

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2976 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java b/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
index 79f6f08..050bc77 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
@@ -30,10 +30,12 @@
 import com.google.gwt.dev.js.ast.JsFunction;
 import com.google.gwt.dev.js.ast.JsIf;
 import com.google.gwt.dev.js.ast.JsModVisitor;
+import com.google.gwt.dev.js.ast.JsNullLiteral;
 import com.google.gwt.dev.js.ast.JsPrefixOperation;
 import com.google.gwt.dev.js.ast.JsProgram;
 import com.google.gwt.dev.js.ast.JsStatement;
 import com.google.gwt.dev.js.ast.JsUnaryOperator;
+import com.google.gwt.dev.js.ast.JsValueLiteral;
 import com.google.gwt.dev.js.ast.JsVars;
 import com.google.gwt.dev.js.ast.JsVisitor;
 import com.google.gwt.dev.js.ast.JsWhile;
@@ -86,8 +88,8 @@
    */
   private class EvalFunctionsAtTopScope extends JsModVisitor {
     private final Set<JsFunction> dontMove = new HashSet<JsFunction>();
-    private final Stack<JsBlock> scopeStack = new Stack<JsBlock>();
     private final Stack<ListIterator<JsStatement>> itrStack = new Stack<ListIterator<JsStatement>>();
+    private final Stack<JsBlock> scopeStack = new Stack<JsBlock>();
 
     @Override
     public void endVisit(JsFunction x, JsContext<JsExpression> ctx) {
@@ -233,6 +235,8 @@
         shortCircuitOr(arg1, arg2, ctx);
       } else if (op == JsBinaryOperator.COMMA) {
         trySimplifyComma(arg1, arg2, ctx);
+      } else if (op == JsBinaryOperator.EQ) {
+        trySimplifyEq(x, arg1, arg2, ctx);
       }
     }
 
@@ -526,6 +530,47 @@
         return jsBlock;
       }
     }
+
+    private JsExpression simplifyEq(JsExpression original, JsExpression arg1,
+        JsExpression arg2) {
+      assert (original != null);
+
+      if (arg1 instanceof JsNullLiteral) {
+        return simplifyNullEq(original, arg2);
+      }
+
+      if (arg2 instanceof JsNullLiteral) {
+        return simplifyNullEq(original, arg1);
+      }
+
+      // no simplification made
+      return original;
+    }
+
+    /**
+     * Simplify exp == null.
+     */
+    private JsExpression simplifyNullEq(JsExpression original, JsExpression exp) {
+      assert (original != null);
+
+      if (exp instanceof JsValueLiteral) {
+        // "undefined" is not a JsValueLiteral, so the only way
+        // the result can be true is if exp is itself a JsNullLiteral
+        boolean result = exp instanceof JsNullLiteral;
+        return program.getBooleanLiteral(result);
+      }
+
+      // no simplification made
+      return original;
+    }
+
+    private void trySimplifyEq(JsExpression original, JsExpression arg1,
+        JsExpression arg2, JsContext<JsExpression> ctx) {
+      JsExpression updated = simplifyEq(original, arg1, arg2);
+      if (updated != original) {
+        ctx.replaceMe(updated);
+      }
+    }
   }
 
   public static boolean exec(JsProgram program) {
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java b/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java
index 41244ed..7abc651 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsProgram.java
@@ -55,6 +55,13 @@
     objectScope = new JsScope(rootScope, "Object");
   }
 
+  public JsBooleanLiteral getBooleanLiteral(boolean truth) {
+    if (truth) {
+      return getTrueLiteral();
+    }
+    return getFalseLiteral();
+  }
+
   /**
    * Gets the {@link JsStatement} to use whenever parsed source include a
    * <code>debugger</code> statement.