Fixes type-tightening bugs for exported methods/fields.

Earlier exported and jstype functions was incorrectly optimized
because of the wrong check.

This patch correctly and minimally escapes optimization paths
for cases where we don't have all access information.

Change-Id: Ibac4a4001dbb70c5c3d8764c4543ef48128d6433
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 9162ede..7d9b5de 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
@@ -473,7 +473,10 @@
 
     @Override
     public void exit(JField x, Context ctx) {
-      if (program.codeGenTypes.contains(x.getEnclosingType())) {
+      // TODO: we should also skip @JsType fields when we implement them.
+      if (program.codeGenTypes.contains(x.getEnclosingType())
+          || program.typeOracle.isExportedField(x)) {
+        // We cannot tighten this field as we don't know all callers.
         return;
       }
       if (!x.isVolatile()) {
@@ -659,6 +662,13 @@
 
     @Override
     public void endVisit(JParameter x, Context ctx) {
+      JMethod currentMethod = getCurrentMethod();
+      if (program.codeGenTypes.contains(currentMethod.getEnclosingType())
+          || program.typeOracle.isExportedMethod(currentMethod)
+          || program.typeOracle.isJsTypeMethod(currentMethod)) {
+        // We cannot tighten this parameter as we don't know all callers.
+        return;
+      }
       tighten(x);
     }
 
@@ -684,8 +694,7 @@
        * Explicitly NOT visiting native methods since we can't infer further
        * type information.
        */
-      return !program.codeGenTypes.contains(x.getEnclosingType()) && !x.isNative()
-          || program.typeOracle.isJsTypeMethod(x) || program.typeOracle.isExportedMethod(x);
+      return !x.isNative();
     }
 
     /**
@@ -734,10 +743,6 @@
       }
       JReferenceType refType = (JReferenceType) x.getType();
 
-      if (program.typeOracle.isJsType(refType)) {
-        return;
-      }
-
       if (refType == program.getTypeNull()) {
         return;
       }
diff --git a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
index 3581d6e..7793d50 100644
--- a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
+++ b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java
@@ -168,6 +168,10 @@
     // Test exported constructor called from JS in module window
     ScriptInjector.fromString("new $wnd.MyClassImpl3();").inject();
     assertTrue(MyClassImpl3.calledFromJsModuleWindow);
+
+    // This is to reproduce the problem where we incorrectly type-tighten an exported method params.
+    ScriptInjector.fromString("$wnd.MyClassImpl3.foo($wnd.newA());").inject();
+    assertTrue(MyClassImpl3.calledFromBar);
   }
 
   public void testCasts() {
diff --git a/user/test/com/google/gwt/core/client/interop/MyClassImpl3.java b/user/test/com/google/gwt/core/client/interop/MyClassImpl3.java
index c71640a..b84fde5 100644
--- a/user/test/com/google/gwt/core/client/interop/MyClassImpl3.java
+++ b/user/test/com/google/gwt/core/client/interop/MyClassImpl3.java
@@ -35,4 +35,23 @@
       Assert.assertEquals(42, foo);
       calledFromJsModuleWindow = true;
   }
+
+  public static boolean calledFromBar = false;
+
+  public static class A {
+    void bar() {
+      calledFromBar = true;
+    }
+  }
+
+  // There should be no calls to this method from java.
+  @JsExport("$wnd.MyClassImpl3.foo")
+  public static void foo(A a) {
+    a.bar();
+  }
+
+  @JsExport("$wnd.newA")
+  private static A newA() {
+    return new A();
+  }
 }