Allow general initializer in @JsOverlay static fields.

Change-Id: If78bcea9baf62683fe10f022e7c1c647582030a3
diff --git a/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java b/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java
index bcd3a93..37d7e7a 100644
--- a/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java
+++ b/dev/core/src/com/google/gwt/dev/javac/testing/impl/JavaResourceBase.java
@@ -377,46 +377,52 @@
   public static final MockJavaResource JSTYPE =
       createMockJavaResource("jsinterop.annotations.JsType",
           "package jsinterop.annotations;",
-          "public @interface JsType {\n",
-          "  String namespace() default \"\";\n",
-          "  String name() default \"\";\n",
-          "  boolean isNative() default false;\n" +
+          "public @interface JsType {",
+          "  String namespace() default \"\";",
+          "  String name() default \"\";",
+          "  boolean isNative() default false;",
           "}"
       );
   public static final MockJavaResource JSCONSTRUCTOR =
       createMockJavaResource("jsinterop.annotations.JsConstructor",
           "package jsinterop.annotations;",
-          "public @interface JsConstructor {\n",
+          "public @interface JsConstructor {",
+          "}");
+  public static final MockJavaResource JSPACKAGE =
+      createMockJavaResource("jsinterop.annotations.JsPackage",
+          "package jsinterop.annotations;",
+          "public @interface JsPackage {",
+          "  String GLOBAL = \"<global>\";",
+          "  String namespace();",
           "}");
   public static final MockJavaResource JSPROPERTY =
       createMockJavaResource("jsinterop.annotations.JsProperty",
           "package jsinterop.annotations;",
-          "public @interface JsProperty {\n",
-          "  String namespace() default \"\";\n",
-          "  String name() default \"\";\n",
+          "public @interface JsProperty {",
+          "  String namespace() default \"\";",
+          "  String name() default \"\";",
           "}");
   public static final MockJavaResource JSMETHOD =
       createMockJavaResource("jsinterop.annotations.JsMethod",
           "package jsinterop.annotations;",
           "public @interface JsMethod {\n",
-          "  String namespace() default \"\";\n",
-          "  String name() default \"\";\n",
+          "  String namespace() default \"\";",
+          "  String name() default \"\";",
           "}");
   public static final MockJavaResource JSIGNORE =
       createMockJavaResource("jsinterop.annotations.JsIgnore",
           "package jsinterop.annotations;",
-          "public @interface JsIgnore {\n",
+          "public @interface JsIgnore {",
           "}");
   public static final MockJavaResource JSFUNCTION =
       createMockJavaResource("jsinterop.annotations.JsFunction",
           "package jsinterop.annotations;",
-          "public @interface JsFunction {\n",
+          "public @interface JsFunction {",
           "}");
-
   public static final MockJavaResource JSOVERLAY =
       createMockJavaResource("jsinterop.annotations.JsOverlay",
           "package jsinterop.annotations;",
-          "public @interface JsOverlay {\n",
+          "public @interface JsOverlay {",
           "}");
 
   public static MockJavaResource[] getStandardResources() {
@@ -426,8 +432,8 @@
         ERROR, FUNCTIONALINTERFACE, FLOAT, INTEGER, IS_SERIALIZABLE, JAVASCRIPTEXCEPTION,
         JAVASCRIPTOBJECT, LIST, LONG, MAP, NO_CLASS_DEF_FOUND_ERROR, NUMBER, OBJECT,
         RUNTIME_EXCEPTION, SERIALIZABLE, SHORT, STRING, STRING_BUILDER, SUPPRESS_WARNINGS, SYSTEM,
-        THROWABLE, SPECIALIZE_METHOD, JSTYPE, JSCONSTRUCTOR, JSPROPERTY, JSMETHOD, JSIGNORE,
-        JSFUNCTION, JSOVERLAY};
+        THROWABLE, SPECIALIZE_METHOD, JSTYPE, JSCONSTRUCTOR, JSPACKAGE, JSPROPERTY, JSMETHOD,
+        JSIGNORE, JSFUNCTION, JSOVERLAY};
   }
 
   /**
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
index 4d26cec..29d8d15 100755
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
@@ -271,7 +271,7 @@
    * superclass, or <code>null</code> if this class has no static initializer.
    */
   public final JDeclaredType getClinitTarget() {
-    if (isJsNative() || isJsFunction()) {
+    if (isJsFunction()) {
       return null;
     }
     return clinitTarget;
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
index be6caaa..4851be5 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
@@ -160,12 +160,12 @@
 
   @Override
   public boolean isJsInteropEntryPoint() {
-    return exported && isStatic() && !isJsNative();
+    return exported && isStatic() && !isJsNative() && !isJsOverlay();
   }
 
   @Override
   public boolean canBeReferencedExternally() {
-    return exported;
+    return exported && !isJsNative();
   }
 
   @Override
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
index d9f155b..250e7f8 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
@@ -72,11 +72,16 @@
 
   @Override
   public boolean isJsInteropEntryPoint() {
-    return exported && !needsDynamicDispatch() && !isJsNative();
+    return exported && !needsDynamicDispatch() && !isJsNative() && !isJsOverlay();
   }
 
   @Override
   public boolean canBeReferencedExternally() {
+    if (isJsOverlay() || (!needsDynamicDispatch() && isJsNative()))  {
+      // JsOverlays, native constructors and native static methods can not be referenced
+      // externally
+      return false;
+    }
     for (JMethod method : getOverriddenMethodsIncludingSelf()) {
       if (method.exported || method.isJsFunctionMethod()) {
         return true;
@@ -244,7 +249,8 @@
 
   @Override
   public boolean isJsOverlay() {
-    return isJsOverlay || getEnclosingType().isJsoType();
+    return isJsOverlay || getEnclosingType().isJsoType() ||
+        getEnclosingType().isJsNative() && JProgram.isClinit(this);
   }
 
   public void setSyntheticAccidentalOverride() {
@@ -310,7 +316,7 @@
   }
 
   public boolean isJsMethodVarargs() {
-    if (getParams().isEmpty() || !canBeReferencedExternally()) {
+    if (getParams().isEmpty() || !(canBeReferencedExternally() || canBeImplementedExternally())) {
       return false;
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
index 9846181..06c84e1 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JsInteropRestrictionChecker.java
@@ -284,9 +284,10 @@
 
     if (member instanceof JField) {
       JField field = (JField) member;
-      if (!field.isCompileTimeConstant()) {
+      if (field.needsDynamicDispatch()) {
         logError(
-            member, "JsOverlay field '%s' can only be a compile time constant.", methodDescription);
+            member, "JsOverlay field '%s' can only be static.",
+            methodDescription);
       }
       return;
     }
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
index 3634fe5..723c155 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/JsInteropRestrictionCheckerTest.java
@@ -1483,21 +1483,31 @@
         "Line 9: JsOverlay method 'void EntryPoint.Buggy.m()' cannot override a supertype method.");
   }
 
-  public void testJsOverlayOnNonFinalMethodAndNonCompileTimeConstantFieldFails() {
+  public void testJsOverlayOnNonFinalMethodAndInstanceFieldFails() {
     addSnippetImport("jsinterop.annotations.JsType");
     addSnippetImport("jsinterop.annotations.JsOverlay");
     addSnippetClassDecl(
         "@JsType(isNative=true) public static class Buggy {",
-        "  @JsOverlay public static int f1 = 2;",
         "  @JsOverlay public final int f2 = 2;",
         "  @JsOverlay public void m() { }",
         "}");
 
     assertBuggyFails(
         "Line 5: Native JsType 'EntryPoint.Buggy' cannot have initializer.",
-        "Line 6: JsOverlay field 'int EntryPoint.Buggy.f1' can only be a compile time constant.",
-        "Line 7: JsOverlay field 'int EntryPoint.Buggy.f2' can only be a compile time constant.",
-        "Line 8: JsOverlay method 'void EntryPoint.Buggy.m()' cannot be non-final nor native.");
+        "Line 6: JsOverlay field 'int EntryPoint.Buggy.f2' can only be static.",
+        "Line 7: JsOverlay method 'void EntryPoint.Buggy.m()' cannot be non-final nor native.");
+  }
+
+  public void testJsOverlayWithStaticInitializerSucceeds() throws Exception {
+    addSnippetImport("jsinterop.annotations.JsType");
+    addSnippetImport("jsinterop.annotations.JsOverlay");
+    addSnippetClassDecl(
+        "@JsType(isNative=true) public static class Buggy {",
+        "  @JsOverlay public final static Object f1 = new Object();",
+        "  @JsOverlay public static int f2 = 2;",
+        "}");
+
+    assertBuggySucceeds();
   }
 
   public void testJsOverlayOnNativeMethodFails() {
diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java
index 66a5adb..8195c77 100644
--- a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -23,6 +23,10 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+
+import jsinterop.annotations.JsOverlay;
+import jsinterop.annotations.JsType;
+
 /**
  * Tests Java 8 features. It is super sourced so that gwt can be compiles under Java 7.
  *
@@ -1284,4 +1288,63 @@
   private void assertContentsInOrder(Iterable<String> contents, String... elements) {
     assertEquals(Arrays.asList(elements).toString(), contents.toString());
   }
+
+  @JsType(isNative = true)
+  interface  NativeJsTypeInterfaceWithStaticInitializationAndFieldAccess {
+    @JsOverlay
+    Object object = new Integer(3);
+  }
+
+  @JsType(isNative = true)
+  interface NativeJsTypeInterfaceWithStaticInitializationAndStaticOverlayMethod {
+    @JsOverlay
+    Object object = new Integer(4);
+
+    @JsOverlay
+    static Object getObject() {
+      return object;
+    }
+  }
+
+// TODO(rluble): uncomment when we allow @JsOverlay methods to be default methods of
+// interfaces
+//  @JsType(isNative = true)
+//  interface NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod {
+//  @JsOverlay
+//    Object object = new Integer(5);
+//
+//    @JsOverlay
+//    default Object getObject() {
+//      return object;
+//    }
+//  }
+//
+//  private native NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod
+//      createNativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod() /*-{
+//    return {};
+//  }-*/;
+
+  @JsType(isNative = true)
+  interface NativeJsTypeInterfaceWithStaticInitialization {
+    @JsOverlay
+    Object object = new Integer(6);
+  }
+
+  @JsType(isNative = true)
+  interface NativeJsTypeInterfaceWithComplexStaticInitialization {
+    @JsOverlay
+    Object object = (Integer) (((int) NativeJsTypeInterfaceWithStaticInitialization.object) + 1);
+  }
+
+  public void testNativeJsTypeWithStaticIntializer() {
+    assertEquals(3, NativeJsTypeInterfaceWithStaticInitializationAndFieldAccess.object);
+    assertEquals(
+        4, NativeJsTypeInterfaceWithStaticInitializationAndStaticOverlayMethod.getObject());
+// TODO(rluble): uncomment when we allow @JsOverlay methods to be default methods of
+// interfaces
+//    assertEquals(new Integer(5),
+//        createNativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod()
+//            .getObject());
+    assertEquals(7, NativeJsTypeInterfaceWithComplexStaticInitialization.object);
+  }
 }
diff --git a/user/test/com/google/gwt/core/interop/JsPropertyTest.java b/user/test/com/google/gwt/core/interop/JsPropertyTest.java
index 875c11b..dbf9b25 100644
--- a/user/test/com/google/gwt/core/interop/JsPropertyTest.java
+++ b/user/test/com/google/gwt/core/interop/JsPropertyTest.java
@@ -245,11 +245,11 @@
     void setX(int x);
   }
 
-  static class MyNativeNativeJsTypeTypeInterfaceSubclassNeedingBridge
-      extends AccidentaImplementer implements MyNativeJsTypeInterface {
+  static class MyNativeJsTypeInterfaceImplementorNeedingBridge
+      extends AccidentalImplementer implements MyNativeJsTypeInterface {
   }
 
-  static abstract class AccidentaImplementer {
+  static abstract class AccidentalImplementer {
     private int x;
 
     public int getX() {
@@ -266,25 +266,25 @@
   }
 
   public void testJsPropertyBridges() {
-    MyNativeJsTypeInterface object = new MyNativeNativeJsTypeTypeInterfaceSubclassNeedingBridge();
+    MyNativeJsTypeInterface object = new MyNativeJsTypeInterfaceImplementorNeedingBridge();
 
     object.setX(3);
     assertEquals(3 + 150, object.getX());
-    assertEquals(3 + SET_X, ((AccidentaImplementer) object).x);
+    assertEquals(3 + SET_X, ((AccidentalImplementer) object).x);
 
-    AccidentaImplementer accidentaImplementer = (AccidentaImplementer) object;
+    AccidentalImplementer accidentalImplementer = (AccidentalImplementer) object;
 
-    accidentaImplementer.setX(3);
-    assertEquals(3 + 150, accidentaImplementer.getX());
+    accidentalImplementer.setX(3);
+    assertEquals(3 + 150, accidentalImplementer.getX());
     assertEquals(3 + 150, getProperty(object, "x"));
-    assertEquals(3 + SET_X, accidentaImplementer.x);
+    assertEquals(3 + SET_X, accidentalImplementer.x);
 
     setProperty(object, "x", 4);
-    assertEquals(4 + 150, accidentaImplementer.getX());
+    assertEquals(4 + 150, accidentalImplementer.getX());
     assertEquals(4 + 150, getProperty(object, "x"));
-    assertEquals(4 + SET_X, accidentaImplementer.x);
+    assertEquals(4 + SET_X, accidentalImplementer.x);
 
-    assertEquals(3 + 4 + SET_X, accidentaImplementer.sum(3));
+    assertEquals(3 + 4 + SET_X, accidentalImplementer.sum(3));
   }
 
   static class MyNativeJsTypeInterfaceImplNeedingBridgeSubclassed
diff --git a/user/test/com/google/gwt/core/interop/JsTypeTest.java b/user/test/com/google/gwt/core/interop/JsTypeTest.java
index 8378c66..1377ed8 100644
--- a/user/test/com/google/gwt/core/interop/JsTypeTest.java
+++ b/user/test/com/google/gwt/core/interop/JsTypeTest.java
@@ -23,10 +23,8 @@
 
 import java.util.Iterator;
 
-import javaemul.internal.annotations.DoNotInline;
 import jsinterop.annotations.JsFunction;
 import jsinterop.annotations.JsMethod;
-import jsinterop.annotations.JsOverlay;
 import jsinterop.annotations.JsPackage;
 import jsinterop.annotations.JsProperty;
 import jsinterop.annotations.JsType;
@@ -479,42 +477,6 @@
     assertSame(3, ((JsFunctionInterface) nativeJsFunction()).m());
   }
 
-  private static native void setProperty(Object object, String name, int value) /*-{
-    object[name] = value;
-  }-*/;
-
-  @JsType(isNative = true, namespace = GLOBAL, name = "Object")
-  static class NativeJsTypeWithOverlay {
-
-    @JsOverlay
-    public static final int x = 2;
-
-    public static native String[] keys(Object o);
-
-    @JsOverlay @DoNotInline
-    public static final boolean hasM(Object obj) {
-      return keys(obj)[0].equals("m");
-    }
-
-    public native boolean hasOwnProperty(String name);
-
-    @JsOverlay @DoNotInline
-    public final boolean hasM() {
-      return hasOwnProperty("m");
-    }
-  }
-
-  private native NativeJsTypeWithOverlay createNativeJsTypeWithOverlay() /*-{
-    return { m: function() { return 6; } };
-  }-*/;
-
-  public void testNativeJsTypeWithOverlay() {
-    NativeJsTypeWithOverlay object = createNativeJsTypeWithOverlay();
-    assertTrue(object.hasM());
-    assertTrue(NativeJsTypeWithOverlay.hasM(object));
-    assertEquals(2, NativeJsTypeWithOverlay.x);
-  }
-
   @JsType
   static abstract class SomeAbstractClass {
     public abstract SomeAbstractClass m();
diff --git a/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java b/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
index 3dd9382..b96a6eb 100644
--- a/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
+++ b/user/test/com/google/gwt/core/interop/NativeJsTypeTest.java
@@ -15,9 +15,14 @@
  */
 package com.google.gwt.core.interop;
 
+import static jsinterop.annotations.JsPackage.GLOBAL;
+
 import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.junit.client.GWTTestCase;
 
+import javaemul.internal.annotations.DoNotInline;
+import jsinterop.annotations.JsOverlay;
+import jsinterop.annotations.JsPackage;
 import jsinterop.annotations.JsType;
 
 /**
@@ -81,4 +86,72 @@
   private static native Object createNativeArray() /*-{
     return [];
   }-*/;
+
+  @JsType(isNative = true, namespace = GLOBAL, name = "Object")
+  static class NativeJsTypeWithOverlay {
+
+    @JsOverlay
+    public static final int x = 2;
+
+    public static native String[] keys(Object o);
+
+    @JsOverlay @DoNotInline
+    public static final boolean hasM(Object obj) {
+      return keys(obj)[0].equals("m");
+    }
+
+    public native boolean hasOwnProperty(String name);
+
+    @JsOverlay @DoNotInline
+    public final boolean hasM() {
+      return hasOwnProperty("m");
+    }
+  }
+
+  private native NativeJsTypeWithOverlay createNativeJsTypeWithOverlay() /*-{
+    return { m: function() { return 6; } };
+  }-*/;
+
+  public void testNativeJsTypeWithOverlay() {
+    NativeJsTypeWithOverlay object = createNativeJsTypeWithOverlay();
+    assertTrue(object.hasM());
+    assertTrue(NativeJsTypeWithOverlay.hasM(object));
+    assertEquals(2, NativeJsTypeWithOverlay.x);
+  }
+
+  @JsType(isNative = true)
+  static class NativeJsTypeWithStaticInitializationAndFieldAccess {
+    @JsOverlay
+    public static Object object = new Integer(3);
+  }
+
+  @JsType(isNative = true)
+  static class NativeJsTypeWithStaticInitializationAndStaticOverlayMethod {
+    @JsOverlay
+    public static Object object = new Integer(4);
+
+    @JsOverlay
+    public static Object getObject() {
+      return object;
+    }
+  }
+
+  @JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
+  static class NativeJsTypeWithStaticInitializationAndInstanceOverlayMethod {
+    @JsOverlay
+    public static Object object = new Integer(5);
+
+    @JsOverlay
+    public final Object getObject() {
+      return object;
+    }
+  }
+
+  public void testNativeJsTypeWithStaticIntializer() {
+    assertEquals(new Integer(3), NativeJsTypeWithStaticInitializationAndFieldAccess.object);
+    assertEquals(
+        new Integer(4), NativeJsTypeWithStaticInitializationAndStaticOverlayMethod.getObject());
+     assertEquals(new Integer(5),
+         new NativeJsTypeWithStaticInitializationAndInstanceOverlayMethod().getObject());
+  }
 }
diff --git a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
index c892a15..d1ff194 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -260,6 +260,10 @@
     assertFalse(isGwtSourceLevel8());
   }
 
+  public void testNativeJsTypeWithStaticIntializer() {
+    assertFalse(isGwtSourceLevel8());
+  }
+
   private boolean isGwtSourceLevel8() {
     return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA8) >= 0;
   }