Adds a -draftCompile flag to the compiler.
Improves the robustness of certain tests.
Runs -draftCompile tests in ant build.

Patch by: bobv, spoon
Review by: spoon, bobv


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4590 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/HostedModeBase.java b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
index 28741a0e..559e5d1 100644
--- a/dev/core/src/com/google/gwt/dev/HostedModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/HostedModeBase.java
@@ -31,6 +31,7 @@
 import com.google.gwt.dev.shell.ShellModuleSpaceHost;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
+import com.google.gwt.dev.util.arg.ArgHandlerDraftCompile;
 import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
 import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
 import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
@@ -319,6 +320,7 @@
       registerHandler(new ArgHandlerScriptStyle(options));
       registerHandler(new ArgHandlerEnableAssertions(options));
       registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
+      registerHandler(new ArgHandlerDraftCompile(options));
     }
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index cb95d6c..d64c2ed 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -42,6 +42,7 @@
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
 import com.google.gwt.dev.util.arg.ArgHandlerDisableRunAsync;
+import com.google.gwt.dev.util.arg.ArgHandlerDraftCompile;
 import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
 import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
 import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
@@ -78,6 +79,7 @@
       registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
       registerHandler(new ArgHandlerValidateOnlyFlag(options));
       registerHandler(new ArgHandlerDisableRunAsync(options));
+      registerHandler(new ArgHandlerDraftCompile(options));
     }
 
     @Override
@@ -88,6 +90,7 @@
 
   static class PrecompileOptionsImpl extends CompileTaskOptionsImpl implements
       PrecompileOptions {
+
     private File genDir;
     private final JJSOptionsImpl jjsOptions = new JJSOptionsImpl();
     private boolean validateOnly;
@@ -120,6 +123,10 @@
       return jjsOptions.isAggressivelyOptimize();
     }
 
+    public boolean isDraftCompile() {
+      return jjsOptions.isDraftCompile();
+    }
+
     public boolean isEnableAssertions() {
       return jjsOptions.isEnableAssertions();
     }
@@ -140,6 +147,10 @@
       jjsOptions.setAggressivelyOptimize(aggressivelyOptimize);
     }
 
+    public void setDraftCompile(boolean draft) {
+      jjsOptions.setDraftCompile(draft);
+    }
+
     public void setEnableAssertions(boolean enableAssertions) {
       jjsOptions.setEnableAssertions(enableAssertions);
     }
@@ -311,8 +322,7 @@
           merged.put(rebindResultsString, permutation);
         }
       }
-      return new Precompilation(unifiedAst, merged.values(),
-          generatedArtifacts);
+      return new Precompilation(unifiedAst, merged.values(), generatedArtifacts);
     } catch (UnableToCompleteException e) {
       // We intentionally don't pass in the exception here since the real
       // cause has been logged.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java b/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
index a762504..7989c6d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
@@ -16,6 +16,7 @@
 package com.google.gwt.dev.jjs;
 
 import com.google.gwt.dev.util.arg.OptionAggressivelyOptimize;
+import com.google.gwt.dev.util.arg.OptionDraftCompile;
 import com.google.gwt.dev.util.arg.OptionEnableAssertions;
 import com.google.gwt.dev.util.arg.OptionRunAsyncEnabled;
 import com.google.gwt.dev.util.arg.OptionScriptStyle;
@@ -25,6 +26,6 @@
  * Controls options for the {@link JavaToJavaScriptCompiler}.
  */
 public interface JJSOptions extends OptionAggressivelyOptimize,
-    OptionEnableAssertions, OptionRunAsyncEnabled, OptionScriptStyle,
-    OptionSoycEnabled {
+    OptionDraftCompile, OptionEnableAssertions, OptionRunAsyncEnabled,
+    OptionScriptStyle, OptionSoycEnabled {
 }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java b/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
index d0742d4..e6827fd 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
@@ -23,6 +23,7 @@
 public class JJSOptionsImpl implements JJSOptions, Serializable {
 
   private boolean aggressivelyOptimize = true;
+  private boolean draftCompile = false;
   private boolean enableAssertions;
   private JsOutputOption output = JsOutputOption.OBFUSCATED;
   private boolean runAsyncEnabled = true;
@@ -37,6 +38,7 @@
 
   public void copyFrom(JJSOptions other) {
     setAggressivelyOptimize(other.isAggressivelyOptimize());
+    setDraftCompile(other.isDraftCompile());
     setEnableAssertions(other.isEnableAssertions());
     setOutput(other.getOutput());
     setRunAsyncEnabled(other.isRunAsyncEnabled());
@@ -51,6 +53,10 @@
     return aggressivelyOptimize;
   }
 
+  public boolean isDraftCompile() {
+    return draftCompile;
+  }
+
   public boolean isEnableAssertions() {
     return enableAssertions;
   }
@@ -67,6 +73,10 @@
     this.aggressivelyOptimize = aggressivelyOptimize;
   }
 
+  public void setDraftCompile(boolean draft) {
+    this.draftCompile = draft;
+  }
+
   public void setEnableAssertions(boolean enableAssertions) {
     this.enableAssertions = enableAssertions;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index d117d02..1dd2a9a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -68,6 +68,7 @@
 import com.google.gwt.dev.jjs.impl.ResolveRebinds;
 import com.google.gwt.dev.jjs.impl.TypeMap;
 import com.google.gwt.dev.jjs.impl.TypeTightener;
+import com.google.gwt.dev.js.EvalFunctionsAtTopScope;
 import com.google.gwt.dev.js.JsIEBlockSizeVisitor;
 import com.google.gwt.dev.js.JsInliner;
 import com.google.gwt.dev.js.JsNormalizer;
@@ -182,6 +183,8 @@
       JsNormalizer.exec(jsProgram);
       // Resolve all unresolved JsNameRefs.
       JsSymbolResolver.exec(jsProgram);
+      // Move all function definitions to a top-level scope, to reduce weirdness
+      EvalFunctionsAtTopScope.exec(jsProgram);
 
       // (9) Optimize the JS AST.
       if (options.isAggressivelyOptimize()) {
@@ -418,8 +421,8 @@
 
       // Recompute clinits each time, they can become empty.
       jprogram.typeOracle.recomputeClinits();
-
       didChange = false;
+
       // Remove unreferenced types, fields, methods, [params, locals]
       didChange = Pruner.exec(jprogram, true) || didChange;
       // finalize locals, params, fields, methods, classes
@@ -447,7 +450,16 @@
       }
       // prove that any types that have been culled from the main tree are
       // unreferenced due to type tightening?
-    } while (didChange);
+    } while (didChange && !options.isDraftCompile());
+
+    if (options.isDraftCompile()) {
+      /*
+       * Ensure that references to dead clinits are removed. Otherwise, the
+       * application won't run reliably.
+       */
+      jprogram.typeOracle.recomputeClinits();
+      DeadCodeElimination.exec(jprogram);
+    }
   }
 
   private static JavaToJavaScriptMap addStringLiteralMap(
diff --git a/dev/core/src/com/google/gwt/dev/js/EvalFunctionsAtTopScope.java b/dev/core/src/com/google/gwt/dev/js/EvalFunctionsAtTopScope.java
new file mode 100644
index 0000000..9455037
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/js/EvalFunctionsAtTopScope.java
@@ -0,0 +1,112 @@
+package com.google.gwt.dev.js;
+
+import com.google.gwt.dev.js.ast.JsBlock;
+import com.google.gwt.dev.js.ast.JsContext;
+import com.google.gwt.dev.js.ast.JsExpression;
+import com.google.gwt.dev.js.ast.JsFunction;
+import com.google.gwt.dev.js.ast.JsModVisitor;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsProgramFragment;
+import com.google.gwt.dev.js.ast.JsStatement;
+
+import java.util.HashSet;
+import java.util.ListIterator;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Force all functions to be evaluated at the top of the lexical scope in
+ * which they reside. This makes {@link StaticEvalVisitor} simpler in that we
+ * no longer have to worry about function declarations within expressions.
+ * After this runs, only statements can contain declarations. Moved functions
+ * will end up just before the statement in which they presently reside.
+ */
+public class EvalFunctionsAtTopScope extends JsModVisitor {
+  private final Set<JsFunction> dontMove = new HashSet<JsFunction>();
+  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) {
+    scopeStack.pop();
+  }
+
+  @Override
+  public void endVisit(JsProgram x, JsContext<JsProgram> ctx) {
+    scopeStack.pop();
+  }
+
+  @Override
+  public void endVisit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+    scopeStack.pop();
+  }
+
+  @Override
+  public boolean visit(JsBlock x, JsContext<JsStatement> ctx) {
+    if (x == scopeStack.peek()) {
+      ListIterator<JsStatement> itr = x.getStatements().listIterator();
+      itrStack.push(itr);
+      while (itr.hasNext()) {
+        JsStatement stmt = itr.next();
+        JsFunction func = JsStaticEval.isFunctionDecl(stmt);
+        // Already at the top level.
+        if (func != null) {
+          dontMove.add(func);
+        }
+        accept(stmt);
+        if (func != null) {
+          dontMove.remove(func);
+        }
+      }
+      itrStack.pop();
+      // Already visited.
+      return false;
+    } else {
+      // Just do normal visitation.
+      return true;
+    }
+  }
+
+  @Override
+  public boolean visit(JsFunction x, JsContext<JsExpression> ctx) {
+    /*
+     * We do this during visit() to preserve first-to-last evaluation order.
+     */
+    if (x.getName() != null && !dontMove.contains(x)) {
+      /*
+       * Reinsert this function into the statement immediately before the
+       * current statement. The current statement will have already been
+       * returned from the current iterator's next(), so we have to
+       * backshuffle one step to get in front of it.
+       */
+      ListIterator<JsStatement> itr = itrStack.peek();
+      itr.previous();
+      itr.add(x.makeStmt());
+      itr.next();
+      ctx.replaceMe(x.getName().makeRef(
+          x.getSourceInfo().makeChild(EvalFunctionsAtTopScope.class,
+              "Shuffled evaluation order")));
+    }
+
+    // Dive into the function itself.
+    scopeStack.push(x.getBody());
+    return true;
+  }
+
+  @Override
+  public boolean visit(JsProgram x, JsContext<JsProgram> ctx) {
+    scopeStack.push(x.getGlobalBlock());
+    return true;
+  }
+
+  @Override
+  public boolean visit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
+    scopeStack.push(x.getGlobalBlock());
+    return true;
+  }
+
+  public static void exec(JsProgram jsProgram) {
+    EvalFunctionsAtTopScope fev = new EvalFunctionsAtTopScope();
+    fev.accept(jsProgram);
+  }
+}
\ No newline at end of file
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 09336f3..12a1d2f 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsStaticEval.java
@@ -34,7 +34,6 @@
 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.JsProgramFragment;
 import com.google.gwt.dev.js.ast.JsStatement;
 import com.google.gwt.dev.js.ast.JsUnaryOperator;
 import com.google.gwt.dev.js.ast.JsValueLiteral;
@@ -46,9 +45,7 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Set;
-import java.util.Stack;
 
 /**
  * Removes JsFunctions that are never referenced in the program.
@@ -82,98 +79,6 @@
   }
 
   /**
-   * Force all functions to be evaluated at the top of the lexical scope in
-   * which they reside. This makes {@link StaticEvalVisitor} simpler in that we
-   * no longer have to worry about function declarations within expressions.
-   * After this runs, only statements can contain declarations. Moved functions
-   * will end up just before the statement in which they presently reside.
-   */
-  private class EvalFunctionsAtTopScope extends JsModVisitor {
-    private final Set<JsFunction> dontMove = new HashSet<JsFunction>();
-    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) {
-      scopeStack.pop();
-    }
-
-    @Override
-    public void endVisit(JsProgram x, JsContext<JsProgram> ctx) {
-      scopeStack.pop();
-    }
-
-    @Override
-    public void endVisit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
-      scopeStack.pop();
-    }
-
-    @Override
-    public boolean visit(JsBlock x, JsContext<JsStatement> ctx) {
-      if (x == scopeStack.peek()) {
-        ListIterator<JsStatement> itr = x.getStatements().listIterator();
-        itrStack.push(itr);
-        while (itr.hasNext()) {
-          JsStatement stmt = itr.next();
-          JsFunction func = isFunctionDecl(stmt);
-          // Already at the top level.
-          if (func != null) {
-            dontMove.add(func);
-          }
-          accept(stmt);
-          if (func != null) {
-            dontMove.remove(func);
-          }
-        }
-        itrStack.pop();
-        // Already visited.
-        return false;
-      } else {
-        // Just do normal visitation.
-        return true;
-      }
-    }
-
-    @Override
-    public boolean visit(JsFunction x, JsContext<JsExpression> ctx) {
-      /*
-       * We do this during visit() to preserve first-to-last evaluation order.
-       */
-      if (x.getName() != null && !dontMove.contains(x)) {
-        /*
-         * Reinsert this function into the statement immediately before the
-         * current statement. The current statement will have already been
-         * returned from the current iterator's next(), so we have to
-         * backshuffle one step to get in front of it.
-         */
-        ListIterator<JsStatement> itr = itrStack.peek();
-        itr.previous();
-        itr.add(x.makeStmt());
-        itr.next();
-        ctx.replaceMe(x.getName().makeRef(
-            x.getSourceInfo().makeChild(EvalFunctionsAtTopScope.class,
-                "Shuffled evaluation order")));
-      }
-
-      // Dive into the function itself.
-      scopeStack.push(x.getBody());
-      return true;
-    }
-
-    @Override
-    public boolean visit(JsProgram x, JsContext<JsProgram> ctx) {
-      scopeStack.push(x.getGlobalBlock());
-      return true;
-    }
-
-    @Override
-    public boolean visit(JsProgramFragment x, JsContext<JsProgramFragment> ctx) {
-      scopeStack.push(x.getGlobalBlock());
-      return true;
-    }
-  }
-
-  /**
    * Creates a minimalist list of statements that must be run in order to
    * achieve the same declaration effect as the visited statements.
    * 
@@ -686,11 +591,9 @@
   }
 
   public boolean execImpl() {
-    EvalFunctionsAtTopScope fev = new EvalFunctionsAtTopScope();
-    fev.accept(program);
     StaticEvalVisitor sev = new StaticEvalVisitor();
     sev.accept(program);
 
-    return fev.didChange() || sev.didChange();
+    return sev.didChange();
   }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDraftCompile.java b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDraftCompile.java
new file mode 100644
index 0000000..20d40cd
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/ArgHandlerDraftCompile.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.util.arg;
+
+import com.google.gwt.util.tools.ArgHandlerFlag;
+
+/**
+ * An ArgHandler to enable draft compiles.
+ */
+public class ArgHandlerDraftCompile extends ArgHandlerFlag {
+
+  private final OptionAggressivelyOptimize optimizeOption;
+  private final OptionDraftCompile draftOption;
+
+  public <T extends OptionDraftCompile & OptionAggressivelyOptimize> ArgHandlerDraftCompile(T option) {
+    this.optimizeOption = option;
+    this.draftOption = option;
+  }
+
+  @Override
+  public String getPurpose() {
+    return "Enable faster, but less-optimized, compilations";
+  }
+
+  @Override
+  public String getTag() {
+    return "-draftCompile";
+  }
+
+  @Override
+  public boolean setFlag() {
+    draftOption.setDraftCompile(true);
+    optimizeOption.setAggressivelyOptimize(false);
+    return true;
+  }
+}
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionDraftCompile.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionDraftCompile.java
new file mode 100644
index 0000000..8c425e3
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionDraftCompile.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.util.arg;
+
+/**
+ * An option that indicates that the majority of optimizations are skipped in
+ * favor of a faster compile time.
+ */
+public interface OptionDraftCompile {
+  boolean isDraftCompile();
+
+  void setDraftCompile(boolean draft);
+}
diff --git a/user/build.xml b/user/build.xml
index e096007..31fe611 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -118,6 +118,14 @@
     </gwt.junit>
   </target>
 
+  <target name="test.web.draft" depends="compile, compile.tests" description="Run only web-mode tests for this project.">
+    <gwt.junit test.args="${test.args} -draftCompile -out www -web" test.out="${junit.out}/${build.host.platform}-web-mode-draft" test.cases="default.web.tests" >
+      <extraclasspaths>
+        <pathelement location="${gwt.build}/out/dev/core/bin-test" />
+      </extraclasspaths>
+    </gwt.junit>
+  </target>
+
   <target name="test" depends="compile, compile.tests" description="Run hosted-mode, web-mode, remoteweb, and selenium tests for this project.">
     <property.ensure name="distro.built" location="${gwt.dev.staging.jar}" message="GWT must be built before performing any tests.  This can be fixed by running ant in the ${gwt.root} directory." />
 
@@ -133,6 +141,7 @@
       <antcall target="remoteweb-test"/>
       <antcall target="test.hosted"/>
       <antcall target="test.web"/>
+      <antcall target="test.web.draft"/>
     </parallel>
     </limit>
   </target>
diff --git a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
index 20807b9..3f744d8 100644
--- a/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/CompilerTest.java
@@ -859,8 +859,8 @@
     assertEquals("1bar", 1 + barShouldInline());
     assertEquals("fbar", 'f' + barShouldInline());
     assertEquals("truebar", true + barShouldInline());
-    assertEquals("3.3bar", 3.3 + barShouldInline());
-    assertEquals("3.3bar", 3.3f + barShouldInline());
+    assertEquals("3.5bar", 3.5 + barShouldInline());
+    assertEquals("3.5bar", 3.5f + barShouldInline());
     assertEquals("27bar", 27L + barShouldInline());
     assertEquals("nullbar", null + barShouldInline());
   }
diff --git a/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java b/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java
index d32c01b..51129e3 100644
--- a/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/CompilerConstantStringTest.java
@@ -27,6 +27,7 @@
  */
 public class CompilerConstantStringTest extends GWTTestCase {
 
+  @Override
   public String getModuleName() {
     return "com.google.gwt.emultest.EmulSuite";
   }
@@ -188,7 +189,12 @@
 
   public void testNull() {
     assertNull(returnNull());
-    String a = returnNull() + returnNull();
+    /*
+     * The ""+ is there because GWT currently does not translate a+b
+     * defensively enough to handle the case that both a and b are null.
+     * Revisit this test if that is ever changed.
+     */
+    String a = "" + returnNull() + returnNull();
     assertEquals("nullnull", a);
   }
 
diff --git a/user/test/com/google/gwt/emultest/java/lang/StringBufferTest.java b/user/test/com/google/gwt/emultest/java/lang/StringBufferTest.java
index b5e2241..e92c177 100644
--- a/user/test/com/google/gwt/emultest/java/lang/StringBufferTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/StringBufferTest.java
@@ -27,6 +27,7 @@
    * @return the module name.
    * @see com.google.gwt.junit.client.GWTTestCase#getModuleName()
    */
+  @Override
   public String getModuleName() {
     return "com.google.gwt.emultest.EmulSuite";
   }
@@ -350,6 +351,7 @@
 
     bld = new StringBuilder();
     bld.append(new Object() {
+      @Override
       public String toString() {
         return "obj";
       }
@@ -423,12 +425,12 @@
     assertEquals("01cd234", bld.toString());
 
     bld = new StringBuilder("01234");
-    bld.insert(2, 1.0);
-    assertEquals("011.0234", bld.toString());
+    bld.insert(2, 1.5);
+    assertEquals("011.5234", bld.toString());
 
     bld = new StringBuilder("01234");
-    bld.insert(2, 1.0F);
-    assertEquals("011.0234", bld.toString());
+    bld.insert(2, 1.5F);
+    assertEquals("011.5234", bld.toString());
 
     bld = new StringBuilder("01234");
     bld.insert(2, 99);
@@ -440,6 +442,7 @@
 
     bld = new StringBuilder("01234");
     bld.insert(2, new Object() {
+      @Override
       public String toString() {
         return "obj";
       }
diff --git a/user/test/com/google/gwt/emultest/java/lang/StringTest.java b/user/test/com/google/gwt/emultest/java/lang/StringTest.java
index 20c1a77..a20a0b6 100644
--- a/user/test/com/google/gwt/emultest/java/lang/StringTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/StringTest.java
@@ -299,7 +299,12 @@
    */
   public void testNull() {
     assertNull(returnNull());
-    String a = returnNull() + returnNull();
+    /*
+     * The ""+ is there because GWT currently does not translate a+b
+     * defensively enough to handle the case that both a and b are null.
+     * Revisit this test if that is ever changed.
+     */
+    String a = "" + returnNull() + returnNull();
     assertEquals("nullnull", a);
   }
 
diff --git a/user/test/com/google/gwt/i18n/client/I18NTest.java b/user/test/com/google/gwt/i18n/client/I18NTest.java
index 394b090..043af2c 100644
--- a/user/test/com/google/gwt/i18n/client/I18NTest.java
+++ b/user/test/com/google/gwt/i18n/client/I18NTest.java
@@ -540,13 +540,13 @@
 
   public void testTypedMessages() {
     TestTypedMessages typed = (TestTypedMessages) GWT.create(TestTypedMessages.class);
-    String expected = "int(0) float(1.2), long(0), boolean(true), Object([], char(a), byte(127), short(-32768);";
-    assertEquals(expected, typed.testAllTypes(0, (float) 1.2, 0, true,
+    String expected = "int(0) float(1.5), long(0), boolean(true), Object([], char(a), byte(127), short(-32768);";
+    assertEquals(expected, typed.testAllTypes(0, (float) 1.5, 0, true,
         new ArrayList<String>(), 'a', Byte.MAX_VALUE, Short.MIN_VALUE));
     String lotsOfInts = typed.testLotsOfInts(1, 2, 3, 4);
     assertEquals("1, 2,3,4 ", lotsOfInts);
-    String oneFloat = typed.simpleMessageTest((float) 2.3);
-    assertEquals("2.3", oneFloat);
+    String oneFloat = typed.simpleMessageTest((float) 2.25);
+    assertEquals("2.25", oneFloat);
     String singleQuotes = typed.testSingleQuotes("arg");
     assertEquals("'A', 'arg', ','", singleQuotes);
     String testSomeObjectTypes = typed.testSomeObjectTypes(new I18NTest(),
diff --git a/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java b/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java
index 66050e9..4ed1cd9 100644
--- a/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java
+++ b/user/test/com/google/gwt/i18n/client/NumberFormat_en_Test.java
@@ -173,7 +173,7 @@
     str = NumberFormat.getFormat("##0.###E0").format(12345);
     assertEquals("12.345E3", str);
 
-    str = NumberFormat.getFormat("##0.####E0").format(789.12345e-9);
+    str = NumberFormat.getFormat("##0.####E0").format(789.12346e-9);
     assertEquals("789.1235E-9", str);
     str = NumberFormat.getFormat("##0.####E0").format(780.e-9);
     assertEquals("780E-9", str);
diff --git a/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java b/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java
index 2fe815d..2f0a55a 100644
--- a/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java
+++ b/user/test/com/google/gwt/i18n/client/NumberFormat_fr_Test.java
@@ -26,6 +26,7 @@
   /**
    * Must refer to a valid module that inherits from com.google.gwt.junit.JUnit.
    */
+  @Override
   public String getModuleName() {
     return "com.google.gwt.i18n.I18NTest_fr";
   }
@@ -147,7 +148,7 @@
     str = NumberFormat.getFormat("##0.###E0").format(12345);
     assertEquals("12,345E3", str);
 
-    str = NumberFormat.getFormat("##0.####E0").format(789.12345e-9);
+    str = NumberFormat.getFormat("##0.####E0").format(789.12346e-9);
     assertEquals("789,1235E-9", str);
     str = NumberFormat.getFormat("##0.####E0").format(780.e-9);
     assertEquals("780E-9", str);