From 2d2ef642a3436bc9a8a20a36aec92653f722f602 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 23 Jan 2020 19:03:47 +0300 Subject: [PATCH] Fix virtual method resolution in code server mode --- .../javascript/rendering/Renderer.java | 18 +++++++--- tests/src/test/java/org/teavm/vm/VMTest.java | 34 +++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index a777f9943..2b4a18616 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -27,7 +27,6 @@ import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.function.IntFunction; -import java.util.stream.Collectors; import org.teavm.ast.AsyncMethodNode; import org.teavm.ast.AsyncMethodPart; import org.teavm.ast.MethodNode; @@ -46,6 +45,7 @@ import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.DummyDebugInformationEmitter; import org.teavm.dependency.DependencyInfo; import org.teavm.diagnostics.Diagnostics; +import org.teavm.model.AccessLevel; import org.teavm.model.ClassReader; import org.teavm.model.ClassReaderSource; import org.teavm.model.ElementModifier; @@ -577,7 +577,8 @@ public class Renderer implements RenderingManager { List virtualMethods = new ArrayList<>(); for (PreparedMethod method : cls.getMethods()) { - if (!method.methodHolder.getModifiers().contains(ElementModifier.STATIC)) { + if (!method.methodHolder.getModifiers().contains(ElementModifier.STATIC) + && method.methodHolder.getLevel() != AccessLevel.PRIVATE) { virtualMethods.add(method.reference); } } @@ -657,8 +658,17 @@ public class Renderer implements RenderingManager { private void collectMethodsToCopyFromInterfaces(ClassReader cls, List targetList) { Set implementedMethods = new HashSet<>(); - implementedMethods.addAll(targetList.stream().map(method -> method.getDescriptor()) - .collect(Collectors.toList())); + ClassReader superclass = cls; + while (superclass != null) { + for (MethodReader method : superclass.getMethods()) { + if (method.getLevel() != AccessLevel.PRIVATE && !method.hasModifier(ElementModifier.STATIC) + && !method.hasModifier(ElementModifier.ABSTRACT) + && !method.getName().equals("")) { + implementedMethods.add(method.getDescriptor()); + } + } + superclass = superclass.getParent() != null ? classSource.get(superclass.getParent()) : null; + } Set visitedClasses = new HashSet<>(); for (String ifaceName : cls.getInterfaces()) { diff --git a/tests/src/test/java/org/teavm/vm/VMTest.java b/tests/src/test/java/org/teavm/vm/VMTest.java index e4e19fe70..434d85a2b 100644 --- a/tests/src/test/java/org/teavm/vm/VMTest.java +++ b/tests/src/test/java/org/teavm/vm/VMTest.java @@ -313,6 +313,40 @@ public class VMTest { assertEquals(23, ReadingStateInClinit.state); } + @Test + public void implementInBaseMethodWithDefault() { + SubclassWithInheritedImplementation o = new SubclassWithInheritedImplementation(); + assertEquals(1, o.x); + assertEquals(2, new SubclassWithInheritedDefaultImplementation().foo()); + } + + static class BaseClassWithImplementation { + public int foo() { + return 1; + } + } + + interface BaseInterfaceWithDefault { + default int foo() { + return 2; + } + } + + static class IntermediateClassInheritingImplementation extends BaseClassWithImplementation { + } + + static class SubclassWithInheritedImplementation extends IntermediateClassInheritingImplementation + implements BaseInterfaceWithDefault { + int x; + + SubclassWithInheritedImplementation() { + x = foo(); + } + } + + static class SubclassWithInheritedDefaultImplementation implements BaseInterfaceWithDefault { + } + interface WithDefaultMethod { default String foo() { return "default";