Fix static initializers for interfaces with default methods.
The previous implementaion was queries JInterfaceType to determine
whether the interafce had default methods. Due to the way GwtAstBuilder
works, JInterfaceType is only a stub object if the type is not
part of the current compilation unit.
Change-Id: Id522ee4a8a8cc64e75d734ef28474efa56233f32
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
index 88983ea..f9c23b7 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtUtil.java
@@ -19,9 +19,11 @@
import com.google.gwt.dev.util.Name.InternalName;
import com.google.gwt.thirdparty.guava.common.base.Function;
import com.google.gwt.thirdparty.guava.common.base.Joiner;
+import com.google.gwt.thirdparty.guava.common.base.Predicate;
import com.google.gwt.thirdparty.guava.common.base.Strings;
import com.google.gwt.thirdparty.guava.common.collect.FluentIterable;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
+import com.google.gwt.thirdparty.guava.common.collect.Iterables;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import org.eclipse.jdt.core.compiler.CharOperation;
@@ -44,6 +46,7 @@
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -445,4 +448,26 @@
ReferenceBinding binding = (ReferenceBinding) typeBinding;
return isJso(binding.superclass());
}
+
+ public static Iterable<ReferenceBinding> getSuperInterfacesRequiringInitialization(
+ ReferenceBinding type) {
+ Iterable<ReferenceBinding> interfaces = Collections.emptyList();
+ for (ReferenceBinding interfaceType : type.superInterfaces()) {
+ interfaces =
+ Iterables.concat(interfaces, getSuperInterfacesRequiringInitialization(interfaceType));
+ if (hasDefaultMethods(interfaceType)) {
+ interfaces = Iterables.concat(interfaces, Collections.singleton(interfaceType));
+ }
+ }
+ return interfaces;
+ }
+
+ private static boolean hasDefaultMethods(ReferenceBinding interfaceType) {
+ return Iterables.any(Arrays.asList(interfaceType.methods()), new Predicate<MethodBinding>() {
+ @Override
+ public boolean apply(MethodBinding methodBinding) {
+ return methodBinding.isDefaultMethod();
+ }
+ });
+ }
}
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 0f52fa3..01f1c27 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,7 @@
}
public boolean hasDefaultMethods() {
+ assert !isExternal();
return Iterables.any(getMethods(), new Predicate<JMethod>() {
@Override
public boolean apply(JMethod method) {
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 02305f3..929e09e 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
@@ -2533,7 +2533,16 @@
// Synthesize super clinit calls.
if (type instanceof JClassType) {
- JjsUtils.synthesizeStaticInitializerChain(type);
+ Iterable<JInterfaceType> interfacesToInitialize =
+ Iterables.transform(
+ JdtUtil.getSuperInterfacesRequiringInitialization(x.binding),
+ new Function<ReferenceBinding, JInterfaceType>() {
+ @Override
+ public JInterfaceType apply(ReferenceBinding referenceBinding) {
+ return (JInterfaceType) typeMap.get(referenceBinding);
+ }
+ });
+ JjsUtils.synthesizeStaticInitializerChain(type, interfacesToInitialize);
}
// Implement getClass() implementation for all non-Object classes.
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
index 8f46b2a..b94ebaf 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JjsUtils.java
@@ -434,7 +434,8 @@
return translatorByLiteralClass.get(literal.getClass()).translate(literal);
}
- static void synthesizeStaticInitializerChain(JDeclaredType type) {
+ static void synthesizeStaticInitializerChain(
+ JDeclaredType type, Iterable<JInterfaceType> superInterfacesRequiringStaticInitialization) {
// Implement static initialization as described in (Java 8) JLS 12.4.2.
List<JStatement> superClinitCalls = Lists.newArrayList();
SourceInfo sourceInfo = type.getSourceInfo();
@@ -447,7 +448,7 @@
}
// Recurse over interfaces in preorder initializing the ones that have default methods.
- for (JInterfaceType interfaceType : getSuperInterfacesRequiringInitialization(type)) {
+ for (JInterfaceType interfaceType : superInterfacesRequiringStaticInitialization) {
superClinitCalls.add(
new JMethodCall(sourceInfo, null, interfaceType.getClinitMethod()).makeStatement());
}
@@ -559,19 +560,6 @@
return emptyMethod;
}
- private static Iterable<JInterfaceType> getSuperInterfacesRequiringInitialization(
- JDeclaredType type) {
- Iterable<JInterfaceType> interfaces = Collections.emptyList();
- for (JInterfaceType interfaceType : type.getImplements()) {
- interfaces =
- Iterables.concat(interfaces, getSuperInterfacesRequiringInitialization(interfaceType));
- if (interfaceType.hasDefaultMethods()) {
- interfaces = Iterables.concat(interfaces, Collections.singleton(interfaceType));
- }
- }
- return interfaces;
- }
-
private JjsUtils() {
}
}
\ No newline at end of file
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 9702bece..66a5adb 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
@@ -16,6 +16,8 @@
package com.google.gwt.dev.jjs.test;
import com.google.gwt.core.client.GwtScriptOnly;
+import com.google.gwt.dev.jjs.test.defaultmethods.ImplementsWithDefaultMethodAndStaticInitializer;
+import com.google.gwt.dev.jjs.test.defaultmethods.SomeClass;
import com.google.gwt.junit.client.GWTTestCase;
import java.util.ArrayList;
@@ -1273,6 +1275,12 @@
assertTrue(p.apply(new B()));
}
+ public void testDefaultMethod_staticInitializer() {
+ SomeClass.initializationOrder = new ArrayList<String>();
+ Object object = ImplementsWithDefaultMethodAndStaticInitializer.someClass;
+ assertContentsInOrder(SomeClass.initializationOrder, "1", "2", "3", "4");
+ }
+
private void assertContentsInOrder(Iterable<String> contents, String... elements) {
assertEquals(Arrays.asList(elements).toString(), contents.toString());
}
diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/ImplementsWithDefaultMethodAndStaticInitializer.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/ImplementsWithDefaultMethodAndStaticInitializer.java
new file mode 100644
index 0000000..397a2f2
--- /dev/null
+++ b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/ImplementsWithDefaultMethodAndStaticInitializer.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.test.defaultmethods;
+
+/**
+ * Classes to test default method defined in different compilation units.
+ */
+public class ImplementsWithDefaultMethodAndStaticInitializer
+ implements WithDefaultMethodAndStaticInitializer {
+ static {
+ SomeClass.initializationOrder.add("3");
+ }
+ public static SomeClass someClass = new SomeClass("4");
+}
\ No newline at end of file
diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/SomeClass.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/SomeClass.java
new file mode 100644
index 0000000..74948c3
--- /dev/null
+++ b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/SomeClass.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.test.defaultmethods;
+
+import java.util.List;
+
+/**
+ * Classes to test default method defined in different compilation units.
+ */
+public class SomeClass {
+
+ public static List<String> initializationOrder;
+
+ SomeClass(String s) {
+ initializationOrder.add(s);
+ }
+}
\ No newline at end of file
diff --git a/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/WithDefaultMethodAndStaticInitializer.java b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/WithDefaultMethodAndStaticInitializer.java
new file mode 100644
index 0000000..d74ae95
--- /dev/null
+++ b/user/test-super/com/google/gwt/dev/jjs/super/com/google/gwt/dev/jjs/test/defaultmethods/WithDefaultMethodAndStaticInitializer.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.jjs.test.defaultmethods;
+
+/**
+ * Classes to test default method defined in different compilation units.
+ */
+public interface WithDefaultMethodAndStaticInitializer {
+ SomeClass someClass = new SomeClass("1");
+ SomeClass someClass2 = new SomeClass("2");
+
+ default SomeClass getGetSomeClass() {
+ return someClass;
+ }
+}
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 adec54d..c892a15 100644
--- a/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
+++ b/user/test/com/google/gwt/dev/jjs/test/Java8Test.java
@@ -144,6 +144,10 @@
assertFalse(isGwtSourceLevel8());
}
+ public void testDefaultMethod_staticInitializer() {
+ assertFalse(isGwtSourceLevel8());
+ }
+
public void testThisRefInDefenderMethod() {
assertFalse(isGwtSourceLevel8());
}