Allow native classes implement native interfaces with overlays.

Native classes implementing interfaces with overlays triggerred a compiler
error due to the fact that overlays in native intefaces are "default"
methods and that the strategy of implementing them consists in creating
the corresponding synthetic override in classes that don't explicitly
implement the method.

Bug: #9440
Bug-Link: https://github.com/gwtproject/gwt/issues/9440
Change-Id: I30a100c4d83f13df61fed57a54afb3b25a153250
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 f204bd0..23f52db 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
@@ -285,7 +285,7 @@
   }
 
   private void checkJsOverlay(JMember member) {
-    if (member.getEnclosingType().isJsoType()) {
+    if (member.getEnclosingType().isJsoType() || member.isSynthetic()) {
       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 f7991aa..f1546d5 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
@@ -1613,7 +1613,7 @@
         "Line 6: Native JsType ''EntryPoint.Buggy'' can only extend native JsType interfaces.");
   }
 
-  public void testNativeJsTypeInterfaceDefenderMethodsFails() {
+  public void testNativeJsTypeInterfaceDefaultMethodsFails() {
     addSnippetImport("jsinterop.annotations.JsType");
     addSnippetImport("jsinterop.annotations.JsOverlay");
     addSnippetClassDecl(
@@ -1626,6 +1626,11 @@
         "@JsType(isNative=true) public interface Buggy extends Interface {",
         "  default void someMethod(){}",
         "  void someOtherMethod();",
+        "}",
+        "public static class SomeOtherClass implements Interface {",
+        "}",
+        "public static class ClassOverridingOverlayTransitively extends SomeOtherClass {",
+        "  public void someOtherMethod() {}",
         "}");
 
     assertBuggyFails(
@@ -1634,7 +1639,9 @@
         "Line 12: Native JsType method 'void EntryPoint.Buggy.someMethod()' should be native "
             + "or abstract.",
         "Line 13: Method 'void EntryPoint.Buggy.someOtherMethod()' cannot override a JsOverlay"
-            + " method 'void EntryPoint.Interface.someOtherMethod()'.");
+            + " method 'void EntryPoint.Interface.someOtherMethod()'.",
+        "Line 18: Method 'void EntryPoint.ClassOverridingOverlayTransitively.someOtherMethod()' "
+            + "cannot override a JsOverlay method 'void EntryPoint.Interface.someOtherMethod()'.");
   }
 
   public void testJsOptionalSucceeds() throws Exception {
@@ -2190,13 +2197,28 @@
         "  public native void m(Object o);",
         "  public native void m(Object[] o);",
         "}",
-        "@JsType public static class Buggy extends Super {",
+        "public static class Buggy extends Super {",
         "  public void n(Object o) { }",
         "}");
 
     assertBuggySucceeds();
   }
 
+  public void testClassesExtendingNativeJsTypeInterfaceWithOverlaySucceeds() throws Exception {
+    addSnippetImport("jsinterop.annotations.JsOverlay");
+    addSnippetImport("jsinterop.annotations.JsType");
+    addSnippetClassDecl(
+        "@JsType(isNative=true) interface Super {",
+        "  @JsOverlay default void fun() {}",
+        "}",
+        "@JsType(isNative=true) abstract static class Buggy implements Super {",
+        "}",
+        "static class JavaSubclass implements Super {",
+        "}");
+
+    assertBuggySucceeds();
+  }
+
   public void testNonJsTypeExtendingNativeJsTypeWithInstanceMethodOverloadsFails() {
     addSnippetImport("jsinterop.annotations.JsType");
     addSnippetClassDecl(
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 8d896cb..6684445 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
@@ -26,6 +26,8 @@
 
 import jsinterop.annotations.JsFunction;
 import jsinterop.annotations.JsOverlay;
+import jsinterop.annotations.JsPackage;
+import jsinterop.annotations.JsProperty;
 import jsinterop.annotations.JsType;
 
 /**
@@ -1672,10 +1674,34 @@
       return null;
     }
   }
-   // Regression test for bug: #9426.
+
+  // Regression test for bug: #9426.
   public void testCorrectNaming() {
     Function<String> f = ClassWithAVeryLoooooooooooooooooooooooooooooooooooongName::m;
     assertNotNull(f);
   }
+
+  @JsType(isNative = true)
+  interface InterfaceWithOverlay {
+
+    @JsProperty
+    int getLength();
+
+    @JsOverlay
+    default int len() {
+      return this.getLength();
+    }
+  }
+
+  @JsType(isNative = true, name = "Object", namespace = JsPackage.GLOBAL)
+  static abstract class SubclassImplementingInterfaceWithOverlay implements InterfaceWithOverlay {
+  }
+
+  // Regression test for bug: #9440
+  public void testInterfaceWithOverlayAndNativeSubclass() {
+    SubclassImplementingInterfaceWithOverlay object =
+        (SubclassImplementingInterfaceWithOverlay) (Object) new int[]{1, 2, 3};
+    assertEquals(3, object.len());
+  }
 }
 
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 ff90ce9..3cf89d1 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -308,6 +308,10 @@
     assertFalse(isGwtSourceLevel8());
   }
 
+  public void testInterfaceWithOverlayAndNativeSubclass() {
+    assertFalse(isGwtSourceLevel8());
+  }
+
   private boolean isGwtSourceLevel8() {
     return JUnitShell.getCompilerOptions().getSourceLevel().compareTo(SourceLevel.JAVA8) >= 0;
   }