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; };