Fix virtual method resolution in code server mode

This commit is contained in:
Alexey Andreev 2020-01-23 19:03:47 +03:00
parent 05ac4b62bf
commit 2d2ef642a3
2 changed files with 48 additions and 4 deletions

View File

@ -27,7 +27,6 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.function.IntFunction; import java.util.function.IntFunction;
import java.util.stream.Collectors;
import org.teavm.ast.AsyncMethodNode; import org.teavm.ast.AsyncMethodNode;
import org.teavm.ast.AsyncMethodPart; import org.teavm.ast.AsyncMethodPart;
import org.teavm.ast.MethodNode; import org.teavm.ast.MethodNode;
@ -46,6 +45,7 @@ import org.teavm.debugging.information.DebugInformationEmitter;
import org.teavm.debugging.information.DummyDebugInformationEmitter; import org.teavm.debugging.information.DummyDebugInformationEmitter;
import org.teavm.dependency.DependencyInfo; import org.teavm.dependency.DependencyInfo;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.AccessLevel;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
@ -577,7 +577,8 @@ public class Renderer implements RenderingManager {
List<MethodReference> virtualMethods = new ArrayList<>(); List<MethodReference> virtualMethods = new ArrayList<>();
for (PreparedMethod method : cls.getMethods()) { 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); virtualMethods.add(method.reference);
} }
} }
@ -657,8 +658,17 @@ public class Renderer implements RenderingManager {
private void collectMethodsToCopyFromInterfaces(ClassReader cls, List<MethodReference> targetList) { private void collectMethodsToCopyFromInterfaces(ClassReader cls, List<MethodReference> targetList) {
Set<MethodDescriptor> implementedMethods = new HashSet<>(); Set<MethodDescriptor> implementedMethods = new HashSet<>();
implementedMethods.addAll(targetList.stream().map(method -> method.getDescriptor()) ClassReader superclass = cls;
.collect(Collectors.toList())); while (superclass != null) {
for (MethodReader method : superclass.getMethods()) {
if (method.getLevel() != AccessLevel.PRIVATE && !method.hasModifier(ElementModifier.STATIC)
&& !method.hasModifier(ElementModifier.ABSTRACT)
&& !method.getName().equals("<init>")) {
implementedMethods.add(method.getDescriptor());
}
}
superclass = superclass.getParent() != null ? classSource.get(superclass.getParent()) : null;
}
Set<String> visitedClasses = new HashSet<>(); Set<String> visitedClasses = new HashSet<>();
for (String ifaceName : cls.getInterfaces()) { for (String ifaceName : cls.getInterfaces()) {

View File

@ -313,6 +313,40 @@ public class VMTest {
assertEquals(23, ReadingStateInClinit.state); 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 { interface WithDefaultMethod {
default String foo() { default String foo() {
return "default"; return "default";