Static verification of interface references
The JVM spec (prior to JDK 6, to keep it simple) implies that static data-flow-based verification is done on methods at class load time, including the parameters to method calls. For object references (pointers) this, as I understand it, assures than the class flowing to a use of a reference either matches the use exactly or can be "widened" to match the use, based on the "widening reference conversions" described in the language spec.
What I can't figure out is that this definition of "widening" does not appear to be applied to interfaces. Rather, "widening" of interfaces appears to be allowed (for static verification, not necessarily source compilation) somewhat blindly. Only if a method is called on an interface and the method is not implemented by the runtime object does an error appear to be generated.
Is this true? If so, is the behavior documented anywhere?
[896 byte] By [
Hotlicksa] at [2007-11-26 20:59:22]

# 1
Here is an example of what I'm describing:
package verify;
public class Main
{
public static void main(String args[]) {
System.out.println("Hello");
foo();
System.out.println("Goodbye");
}
public static void foo() {
System.out.println("Entered Main.foo");
B b = new rB();
b.methodA();
}
}
package verify;
public interface A {
public void methodA();
}
package verify;
public interface B
// extends A
{
public void methodB();
}
package verify;
public class rB implements B {
/*
public void methodA() {
System.out.println("Inside B.methodA");
}
*/
public void methodB() {
System.out.println("Inside B.methodB");
}
}
The above is compiled initially with the commented lines included, then the lines are commented out and the two changed files are recompiled.
...> java -verify -Xverify -Xfuture verify.Main
Hello
Entered Main.foo
Exception in thread "main" java.lang.IncompatibleClassChangeError: class verify.rB does not implement interface verify.A
at verify.Main.foo(Main.java:12)
at verify.Main.main(Main.java:6)
As can be seen, the Main class loads successfully and the method foo is successfully invoked. No error is detected until the call to methodA is attempted.
The "b.methodA();" statement is compiled as an invokeinterface on verify.A.methodA, but when Main is loaded and method foo invoked the variable b cannot be widened to an A. This is easily determined by static class flow analysis, and would most certainly result in a VerifyError if classes were involved rather than interfaces. Why is the class even allowed to begin execution?