Fix qualified super reference dispatch.
Bug: #9614
Bug-Link: https://github.com/gwtproject/gwt/issues/9614
Change-Id: I54bf51dd32744b12d3d8e279eaebaf284560700c
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
index 07178c7..656fc3a 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
@@ -1553,11 +1553,8 @@
JMethodCall methodCall = new JMethodCall(info, receiver, method);
- // On a super ref, don't allow polymorphic dispatch. Oddly enough,
- // QualifiedSuperReference not derived from SuperReference!
- boolean isSuperRef =
- x.receiver instanceof SuperReference || x.receiver instanceof QualifiedSuperReference;
- if (isSuperRef) {
+ // On a super ref, don't allow polymorphic dispatch.
+ if (isSuperReference(x.receiver)) {
methodCall.setStaticDispatchOnly();
}
@@ -1885,7 +1882,7 @@
// For static methods, instance will be null
samCall = new JMethodCall(info, instance, referredMethod);
// if super::method, we need static dispatch
- if (x.lhs instanceof SuperReference) {
+ if (isSuperReference(x.lhs)) {
samCall.setStaticDispatchOnly();
}
}
@@ -4471,6 +4468,13 @@
}
}
+ /**
+ * Returns <code>true</code> if the expression is either unqualified or qualified super reference.
+ */
+ private static boolean isSuperReference(Expression expression) {
+ return expression instanceof SuperReference || expression instanceof QualifiedSuperReference;
+ }
+
static class JdtPrivateHacks {
/**
* Reflective access to {@link ForeachStatement#collectionElementType}.
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java
index fd3f5df..62f8b83 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/Java8AstTest.java
@@ -19,11 +19,14 @@
import com.google.gwt.dev.javac.testing.impl.MockJavaResource;
import com.google.gwt.dev.jjs.ast.JClassType;
import com.google.gwt.dev.jjs.ast.JConstructor;
+import com.google.gwt.dev.jjs.ast.JDeclaredType;
+import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JMethodBody;
import com.google.gwt.dev.jjs.ast.JPrimitiveType;
import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JReturnStatement;
import com.google.gwt.thirdparty.guava.common.base.Joiner;
import java.util.Collections;
@@ -1208,6 +1211,76 @@
compileSnippetToJS(entryPointClass);
}
+ public void testSuperReferenceExpression() throws Exception {
+ addAll(JavaResourceBase.createMockJavaResource("test.I",
+ "package test;",
+ "interface I {",
+ " int get();",
+ "}"
+ ));
+ addAll(JavaResourceBase.createMockJavaResource("test.Y",
+ "package test;",
+ "class Y {",
+ " int foo(){",
+ " return 42;",
+ " }",
+ "}"
+ ));
+ addAll(JavaResourceBase.createMockJavaResource("test.X",
+ "package test;",
+ "class X extends Y {",
+ " int foo(){",
+ " I i = super::foo;",
+ " return i.get();",
+ " }",
+ "}"
+ ));
+
+ JProgram program = compileSnippet("void", "new X().foo();");
+
+ JDeclaredType methodReferenceType = (JDeclaredType) findType(program, "X$0methodref$foo$Type");
+ JField outerField = methodReferenceType.getFields().get(0);
+ JMethod referenceMethod = findMethod(methodReferenceType, "get");
+ JMethodBody methodBody = (JMethodBody) referenceMethod.getBody();
+ JReturnStatement returnStatement = (JReturnStatement) methodBody.getStatements().get(0);
+ assertEquals("this." + outerField.getName() + ".Y.foo()", returnStatement.getExpr().toSource());
+ }
+
+ public void testQualifiedSuperReferenceExpression() throws Exception {
+ addAll(JavaResourceBase.createMockJavaResource("test.I",
+ "package test;",
+ "interface I {",
+ " int get();",
+ "}"
+ ));
+ addAll(JavaResourceBase.createMockJavaResource("test.Y",
+ "package test;",
+ "class Y {",
+ " int foo(){",
+ " return 42;",
+ " }",
+ "}"
+ ));
+ addAll(JavaResourceBase.createMockJavaResource("test.X",
+ "package test;",
+ "class X extends Y {",
+ " int foo(){",
+ " I i = X.super::foo;",
+ " return i.get();",
+ " }",
+ "}"
+ ));
+
+ JProgram program = compileSnippet("void", "new X().foo();");
+
+ JDeclaredType methodReferenceType = (JDeclaredType) findType(program, "X$0methodref$foo$Type");
+ JField outerField = methodReferenceType.getFields().get(0);
+ JMethod referenceMethod = findMethod(methodReferenceType, "get");
+ JMethodBody methodBody = (JMethodBody) referenceMethod.getBody();
+ JReturnStatement returnStatement = (JReturnStatement) methodBody.getStatements().get(0);
+ assertEquals("this." + outerField.getName() + ".Y.foo()", returnStatement.getExpr().toSource());
+ }
+
@Override
protected void optimizeJava() {
}
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 63b6e6c..907d9f3 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
@@ -371,6 +371,27 @@
assertEquals(42, new X().goo());
}
+ public void testQualifiedSuperReferenceExpression() {
+ class Y {
+ int foo(Integer i) {
+ return 42;
+ }
+ }
+
+ class X extends Y {
+ int foo(Integer i) {
+ return 23;
+ }
+
+ int goo() {
+ I i = X.super::foo;
+ return i.foo(0);
+ }
+ }
+
+ assertEquals(42, new X().goo());
+ }
+
static class X2 {
protected int field;
void foo() {
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 1c20945..312d70c 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -112,6 +112,10 @@
assertFalse(isGwtSourceLevel9());
}
+ public void testQualifiedSuperReferenceExpression() {
+ assertFalse(isGwtSourceLevel9());
+ }
+
public void testSuperReferenceExpressionWithVarArgs() {
assertFalse(isGwtSourceLevel9());
}