From: jtoman Date: Sat, 1 Sep 2018 19:50:00 +0000 (-0700) Subject: Fixes default method resolution (#159) X-Git-Url: http://plrg.eecs.uci.edu/git/?p=jpf-core.git;a=commitdiff_plain;h=d0a18eb873b7a2c18a61d0a6207e00cf04d50f44 Fixes default method resolution (#159) * Fixes default method resolution --- diff --git a/src/main/gov/nasa/jpf/vm/ClassInfo.java b/src/main/gov/nasa/jpf/vm/ClassInfo.java index d9e5331..83b3f5b 100644 --- a/src/main/gov/nasa/jpf/vm/ClassInfo.java +++ b/src/main/gov/nasa/jpf/vm/ClassInfo.java @@ -1091,17 +1091,21 @@ public class ClassInfo extends InfoObject implements Iterable, Gener public MethodInfo getDefaultMethod (String uniqueName) { MethodInfo mi = null; - for (ClassInfo ci = this; ci != null; ci = ci.superClass){ - for (ClassInfo ciIfc : ci.interfaces){ - MethodInfo miIfc = ciIfc.getMethod(uniqueName, true); - if (miIfc != null && !miIfc.isAbstract()){ - if (mi != null && !mi.equals(miIfc)){ + for (ClassInfo ciIfc : this.getAllInterfaces()){ + MethodInfo miIfc = ciIfc.getMethod(uniqueName, false); + if (miIfc != null && !miIfc.isAbstract() && !miIfc.isPrivate() && !miIfc.isStatic()){ + if (mi != null && !mi.equals(miIfc)){ + if(miIfc.getClassInfo().isSubInterfaceOf(mi.getClassInfo())) { + mi = miIfc; + } else if(mi.getClassInfo().isSubInterfaceOf(miIfc.getClassInfo())) { + continue; + } else { // this has to throw a IncompatibleClassChangeError in the client since Java prohibits ambiguous default methods String msg = "Conflicting default methods: " + mi.getFullName() + ", " + miIfc.getFullName(); throw new ClassChangeException(msg); - } else { - mi = miIfc; } + } else { + mi = miIfc; } } } @@ -1109,6 +1113,11 @@ public class ClassInfo extends InfoObject implements Iterable, Gener return mi; } + private boolean isSubInterfaceOf(ClassInfo classInfo) { + assert this.isInterface() && classInfo.isInterface(); + return this == classInfo || this.getAllInterfaces().contains(classInfo); + } + /** * This retrieves the SAM from this functional interface. Note that this is only * called on functional interface expecting to have a SAM. This shouldn't expect diff --git a/src/tests/java8/DefaultMethodTest.java b/src/tests/java8/DefaultMethodTest.java index d1c8977..70f00b2 100644 --- a/src/tests/java8/DefaultMethodTest.java +++ b/src/tests/java8/DefaultMethodTest.java @@ -140,7 +140,63 @@ public class DefaultMethodTest extends TestJPF { o.bar(); } } + // -- most specific implementations + + public static interface Intf1 { + default int getInt() { + return 4; + } + } + + public static interface Intf2 extends Intf1 { + @Override + default int getInt() { + return 3; + } + } + public static abstract class A implements Intf1 { + + } + + public static class B extends A implements Intf2 { + } + + @Test + public void testMostSpecificImplementationResolution() { + if(verifyNoPropertyViolation()) { + B b = new B(); + int x = b.getInt(); + assertEquals(x, 3); + } + } + // --- inherited default methods + + interface SuperIntf { + default String getString() { + return "Hello World"; + } + } + + interface SubIntf extends SuperIntf { + default int getZero() { + return 0; + } + } + + public class ConcreteClass implements SubIntf { + + } + + @Test + public void testInheritedDefaultMethod() { + if(verifyNoPropertyViolation()) { + ConcreteClass cls = new ConcreteClass(); + assertEquals(cls.getString(), "Hello World"); + } + } + // <2do> how to test IncompatibleClassChangeError without explicit classfile restore? } +