Make JsFunction implementation behave exactly as native functions. JsFunctions no longer copy j.l.Object methods/properties into their prototypes effectively behaving like native JS functions. Bug: #9366 Bug-Link: http://github.com/gwtproject/gwt/issues/9366 Change-Id: I1d90f2606f099f53b458eed145b2e9ad459e50d3
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java index 572af74..13ed73a 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JArrayType.java
@@ -127,6 +127,11 @@ } @Override + public boolean isJsFunctionImplementation() { + return false; + } + + @Override public boolean isJsNative() { return getLeafType().isJsNative(); }
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 3d4e8b0..86012c5 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
@@ -379,10 +379,6 @@ return isJsFunction; } - public boolean isJsFunctionImplementation() { - return false; - } - public boolean isClassWideExport() { return isClassWideExport; }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java index be8f9c3..b633e7e 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java
@@ -77,6 +77,11 @@ } @Override + public boolean isJsFunctionImplementation() { + return false; + } + + @Override public boolean isJavaLangObject() { return false; }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java index 8e62df3..6475060 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JPrimitiveType.java
@@ -95,6 +95,11 @@ } @Override + public boolean isJsFunctionImplementation() { + return false; + } + + @Override public boolean isJsNative() { return false; }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java index e3611d2..205e133 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JReferenceType.java
@@ -81,6 +81,11 @@ } @Override + public boolean isJsFunctionImplementation() { + return false; + } + + @Override public boolean isJsNative() { return false; } @@ -212,6 +217,11 @@ } @Override + public boolean isJsFunctionImplementation() { + return ref.isJsFunctionImplementation(); + } + + @Override public boolean isJsoType() { return ref.isJsoType(); }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java index 4dfe990..a6406cd 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JType.java
@@ -76,6 +76,8 @@ public abstract boolean isJsFunction(); + public abstract boolean isJsFunctionImplementation(); + public abstract boolean isJsNative(); public abstract boolean canBeImplementedExternally();
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java index b076ab3..133cd79 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -2001,12 +2001,20 @@ RuntimeConstants.RUNTIME_DEFINE_CLASS, defineClassArguments).makeStmt(); addTypeDefinitionStatement(type, defineClassStatement); - if (jsPrototype != null) { + maybeCopyObjProperties( + type, + getPrototypeQualifierViaLookup(program.getTypeJavaLangObject(), type.getSourceInfo()), + globalTemp.makeRef(type.getSourceInfo())); + } + + private void maybeCopyObjProperties( + JDeclaredType type, JsExpression toPrototype, JsExpression fromPrototype) { + if (getSuperPrototype(type) != null && !type.isJsFunctionImplementation()) { JsStatement statement = constructInvocation(type.getSourceInfo(), RuntimeConstants.RUNTIME_COPY_OBJECT_PROPERTIES, - getPrototypeQualifierViaLookup(program.getTypeJavaLangObject(), type.getSourceInfo()), - globalTemp.makeRef(type.getSourceInfo())) + fromPrototype, + toPrototype) .makeStmt(); addTypeDefinitionStatement(type, statement); } @@ -2134,14 +2142,10 @@ // inline assignment of castableTypeMap field instead of using defineClass() setupCastMapOnPrototype(type); - if (jsPrototype != null) { - JsStatement statement = - constructInvocation(info, - RuntimeConstants.RUNTIME_COPY_OBJECT_PROPERTIES, - getPrototypeQualifierOf(program.getTypeJavaLangObject(), info), - getPrototypeQualifierOf(type, info)).makeStmt(); - addTypeDefinitionStatement(type, statement); - } + maybeCopyObjProperties( + type, + getPrototypeQualifierOf(program.getTypeJavaLangObject(), info), + getPrototypeQualifierOf(type, info)); } private void setupCastMapOnPrototype(JDeclaredType type) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java index 11d373a..3006bda 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/ImplementClassLiteralsAsFields.java
@@ -469,7 +469,7 @@ * </pre> */ private JField resolveClassLiteralField(JType type) { - type = type.isJsNative() + type = type.isJsNative() || type.isJsFunction() || type.isJsFunctionImplementation() ? program.getJavaScriptObject() : program.normalizeJsoType(type); JField field = classLiteralFields.get(type); if (field == null) {
diff --git a/user/test/com/google/gwt/core/interop/JsFunctionTest.java b/user/test/com/google/gwt/core/interop/JsFunctionTest.java index b71d71a..8423f77 100644 --- a/user/test/com/google/gwt/core/interop/JsFunctionTest.java +++ b/user/test/com/google/gwt/core/interop/JsFunctionTest.java
@@ -256,6 +256,57 @@ assertSame(jsFuncionProperty.func.m(), funcInVar.m()); } + public void testGetClass() { + + MyJsFunctionInterface jsfunctionImplementation = + new MyJsFunctionInterface() { + @Override + public int foo(int a) { + return a; + } + }; + assertEquals(MyJsFunctionInterface.class, jsfunctionImplementation.getClass()); + assertEquals(MyJsFunctionInterface.class, ((Object) jsfunctionImplementation).getClass()); + assertEquals(MyJsFunctionInterface.class, createMyJsFunction().getClass()); + assertEquals(MyJsFunctionInterface.class, ((Object) createMyJsFunction()).getClass()); + } + + public void testGetClassA() { + + MyJsFunctionInterface jsfunctionImplementation = + new MyJsFunctionInterface() { + @Override + public int foo(int a) { + return a; + } + }; + assertEquals(MyJsFunctionInterface.class, ((Object) jsfunctionImplementation).getClass()); + } + + public void testGetClassB() { + + MyJsFunctionInterface jsfunctionImplementation = + new MyJsFunctionInterface() { + @Override + public int foo(int a) { + return a; + } + }; + assertEquals(MyJsFunctionInterface.class, createMyJsFunction().getClass()); + } + + public void testGetClassC() { + + MyJsFunctionInterface jsfunctionImplementation = + new MyJsFunctionInterface() { + @Override + public int foo(int a) { + return a; + } + }; + assertEquals(MyJsFunctionInterface.class, ((Object) createMyJsFunction()).getClass()); + } + // uncomment when Java8 is supported. // public void testJsFunctionLambda_JS() { // MyJsFunctionInterface jsFunctionInterface = a -> { return a + 2; };