This is a needed fix in the interface between the compiler (javac) and the metafactory (in java.lang.invoke). So changes to both sides are needed. The interface is the bootstrap parameters of an invokedynamic call. The name should be encoded as a String and the type as a MethodType.
Currently a MethodHandle is used to pass the SAM method type and name. Using MethodHandle is conceptually wrong since, due to separate compilation, the class information may be incorrect at run-time. In these cases, a failure (which should not occur) will happen at run-time. For example:
I.java:
interface I {
}
interface J extends I {
int m(int x);
}
C.java:
class C {
public static void main(String... args) {
J jj = x -> x * x;
System.out.println(jj.m(9));
}
}
After C.java is compiled, I.java is re-compiled as:
interface I {
int m(int x);
}
interface J extends I {
}
When run:
Exception in thread "main" java.lang.IncompatibleClassChangeError
at
java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:384)
at C.main(C.java)
Caused by: java.lang.IllegalAccessException: no such method:
J.m(int)int/invokeInterface
at
java.lang.invoke.MemberName.makeAccessException(MemberName.java:759)
at
java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:880)
at
java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1037)
at
java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1341)
at
java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:382)
... 1 more
Caused by: java.lang.AbstractMethodError: J.m(I)I
at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at
java.lang.invoke.MemberName$Factory.resolve(MemberName.java:852)
at
java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:877)
... 4 more