Implement @JsOverlay with default methods in Java8. Change-Id: Ie7bcdc86b44a7fe33b6ba2e273d2c23351810354
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 250e7f8..6a850ff 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
@@ -249,8 +249,9 @@ @Override public boolean isJsOverlay() { - return isJsOverlay || getEnclosingType().isJsoType() || - getEnclosingType().isJsNative() && JProgram.isClinit(this); + return isJsOverlay + || getEnclosingType().isJsoType() + || getEnclosingType().isJsNative() && JProgram.isClinit(this); } public void setSyntheticAccidentalOverride() {
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 06c84e1..4a15b35 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
@@ -239,6 +239,10 @@ checkMemberOfNativeJsType(member); } + if (member.needsDynamicDispatch()) { + checkIllegalOverrides(member); + } + if (member.isJsOverlay()) { checkJsOverlay(member); return; @@ -271,6 +275,22 @@ } } + private void checkIllegalOverrides(JMember member) { + if (member instanceof JField) { + return; + } + + JMethod method = (JMethod) member; + for (JMethod overriddeMethod : method.getOverriddenMethods()) { + if (overriddeMethod.isJsOverlay()) { + logError(member, "Method '%s' cannot override a JsOverlay method '%s'.", + JjsUtils.getReadableDescription(method), + JjsUtils.getReadableDescription(overriddeMethod)); + return; + } + } + } + private void checkJsOverlay(JMember member) { if (member.getEnclosingType().isJsoType()) { return; @@ -299,7 +319,8 @@ return; } - if (method.getBody() == null || (!method.isFinal() && !method.isStatic())) { + if (method.getBody() == null || (!method.isFinal() && !method.isStatic() + && !method.isDefaultMethod())) { logError(member, "JsOverlay method '%s' cannot be non-final nor native.", methodDescription); }
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 723c155..abbff0b 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
@@ -1417,21 +1417,40 @@ "Line 6: Native JsType ''EntryPoint.Buggy'' can only extend native JsType interfaces."); } - public void testNativeJsTypeInterfaceDefenderMethodsFails() throws Exception { + public void testNativeJsTypeInterfaceDefenderMethodsFails() { + addSnippetImport("jsinterop.annotations.JsType"); + addSnippetImport("jsinterop.annotations.JsOverlay"); + addSnippetClassDecl( + "@JsType(isNative=true) public interface Interface {", + " @JsOverlay default void someOtherMethod(){}", + "}", + "public static class OtherClass implements Interface {", + " public void someOtherMethod() {}", + "}", + "@JsType(isNative=true) public interface Buggy extends Interface {", + " default void someMethod(){}", + " void someOtherMethod();", + "}"); + + assertBuggyFails( + "Line 9: Method 'void EntryPoint.OtherClass.someOtherMethod()' cannot override a " + + "JsOverlay method 'void EntryPoint.Interface.someOtherMethod()'.", + "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()'."); + } + + public void testJsOverlayOnNativeJsTypeInterfaceSucceds() throws Exception { addSnippetImport("jsinterop.annotations.JsType"); addSnippetImport("jsinterop.annotations.JsOverlay"); addSnippetClassDecl( "@JsType(isNative=true) public interface Buggy {", - " default void someMethod(){}", - " @JsOverlay", - " default void someOverlayMethod(){}", + " @JsOverlay Object obj = new Object();", + " @JsOverlay default void someOverlayMethod(){}", "}"); - assertBuggyFails( - "Line 6: Native JsType method 'void EntryPoint.Buggy.someMethod()' should be native " - + "or abstract.", - "Line 8: JsOverlay method 'void EntryPoint.Buggy.someOverlayMethod()' cannot be " - + "non-final nor native."); + assertBuggySucceeds(); } public void testJsOverlayOnNativeJsTypeMemberSucceeds() throws Exception { @@ -1439,7 +1458,7 @@ addSnippetImport("jsinterop.annotations.JsOverlay"); addSnippetClassDecl( "@JsType(isNative=true) public static class Buggy {", - " @JsOverlay public static final int f = 2;", + " @JsOverlay public static Object object = new Object();", " @JsOverlay public static void m() { }", " @JsOverlay public static void m(int x) { }", " @JsOverlay private static void m(boolean x) { }",
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 8195c77..6b829f0 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
@@ -25,6 +25,7 @@ import java.util.List; import jsinterop.annotations.JsOverlay; +import jsinterop.annotations.JsProperty; import jsinterop.annotations.JsType; /** @@ -1306,23 +1307,24 @@ } } -// 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 NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod { + @JsOverlay + Object object = new Integer(5); + + @JsProperty + int getA(); + + @JsOverlay + default Object getObject() { + return ((int) object) + this.getA(); + } + } + + private native NativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod + createNativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod() /*-{ + return {a: 1}; + }-*/; @JsType(isNative = true) interface NativeJsTypeInterfaceWithStaticInitialization { @@ -1340,11 +1342,9 @@ 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(6, + createNativeJsTypeInterfaceWithStaticInitializationAndInstanceOverlayMethod() + .getObject()); assertEquals(7, NativeJsTypeInterfaceWithComplexStaticInitialization.object); } }