TypeTightener was incorrectly treating +=.
TypeTightener was treating += as if it were just an assignment
resulting in suboptimal and potentially incorrect results. E.g.
in "String s = null; s += null;", "s" was determined to be always
null where it clearly is "nullnull" after the second statemetn.
Change-Id: Ia8ec7eaf1a94804789752b8da445bec0bdcb702f
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
index bcef5f6..b29c1cf 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
@@ -21,6 +21,7 @@
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JArrayRef;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
+import com.google.gwt.dev.jjs.ast.JBinaryOperator;
import com.google.gwt.dev.jjs.ast.JCastOperation;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConditional;
@@ -223,7 +224,8 @@
if (x.isAssignment() && (x.getType() instanceof JReferenceType)) {
JExpression lhs = x.getLhs();
if (lhs instanceof JVariableRef) {
- addAssignment(((JVariableRef) lhs).getTarget(), x.getRhs());
+ addAssignment(((JVariableRef) lhs).getTarget(),
+ x.getOp() == JBinaryOperator.ASG ? x.getRhs() : x);
} else {
assert lhs instanceof JArrayRef;
}
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/TypeTightenerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/TypeTightenerTest.java
index fc5c4e8..d66b0a3 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/TypeTightenerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/TypeTightenerTest.java
@@ -45,6 +45,16 @@
result.intoString("null a = null;", "null.nullField += null;");
}
+ public void testBinaryOperation_notNullable() throws Exception {
+ optimize("void", "String other; String s = \"\"; s += null; if (s == null) { other = \"\"; } ")
+ .intoString("null other;", "String s = \"\";", "s += null;");
+ }
+
+ public void testBinaryOperation_nullableButNotNull() throws Exception {
+ optimize("void", "String s = null; s += null;")
+ .intoString("String s = null;", "s += null;");
+ }
+
public void testCastOperation() throws Exception {
addSnippetClassDecl("static class A { " + "String name; public void set() { name = \"A\";} }");
addSnippetClassDecl("static class B extends A {" + "public void set() { name = \"B\";} }");
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 449995c..958cc9b 100644
--- a/user/test/com/google/gwt/emultest/java/lang/StringTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/StringTest.java
@@ -519,13 +519,26 @@
assertTrue("12t", hideFromCompiler("none").matches("^|none$"));
}
- /*
- * TODO: needs rewriting to avoid compiler optimizations.
- */
public void testNull() {
- assertNull(returnNull());
- String a = returnNull() + returnNull();
- assertEquals("nullnull", a);
+ {
+ assertNull(returnNull());
+ String a = returnNull() + returnNull();
+ assertEquals("nullnull", a);
+
+ String s = returnNull();
+ s += returnNull();
+ assertEquals("nullnull", s);
+ }
+
+ // Same tests allowing the compiler to propagate constants.
+ {
+ String a = null + (String) null;
+ assertEquals("nullnull", a);
+
+ String s = null;
+ s += null;
+ assertEquals("nullnull", s);
+ }
}
public void testRegionMatches() {
@@ -804,6 +817,11 @@
}-*/;
private String returnNull() {
+ if (Math.random() < -1) {
+ // Can never happen, but fools the compiler enough not to optimize this call.
+ fail();
+ return "";
+ }
return null;
}