Lambda expression fails with a java.lang.BootstrapMethodError at runtime
<p>In one package (<code>a</code>) I have two functional interfaces:</p>

<pre><code>package a;

@FunctionalInterface
interface Applicable&lt;A extends Applicable&lt;A&gt;&gt; {

    void apply(A self);
}
</code></pre>

<p>-</p>

<pre><code>package a;

@FunctionalInterface
public interface SomeApplicable extends Applicable&lt;SomeApplicable&gt; {
}
</code></pre>

<p>The <code>apply</code> method in the superinterface takes <code>self</code> as an <code>A</code> because otherwise, if <code>Applicable&lt;A&gt;</code> was used instead, the type would not be visible outside the package and therefore the method couldn't be implemented.</p>

<p>In another package (<code>b</code>), I have the following <code>Test</code> class:</p>

<pre><code>package b;

import a.SomeApplicable;

public class Test {

    public static void main(String[] args) {

        // implement using an anonymous class
        SomeApplicable a = new SomeApplicable() {
            @Override
            public void apply(SomeApplicable self) {
                System.out.println("a");
            }
        };
        a.apply(a);

        // implement using a lambda expression
        SomeApplicable b = (SomeApplicable self) -&gt; System.out.println("b");
        b.apply(b);
    }
}
</code></pre>

<p>The first implementation uses an anonymous class and it works with no problem. The second one, on the other hand, compiles fine but fails at runtime throwing a <code>java.lang.BootstrapMethodError</code> caused by a <code>java.lang.IllegalAccessError</code> as it tries to access the <code>Applicable</code> interface.</p>

<pre><code>Exception in thread "main" java.lang.BootstrapMethodError: java.lang.IllegalAccessError: tried to access class a.Applicable from class b.Test
    at b.Test.main(Test.java:19)
Caused by: java.lang.IllegalAccessError: tried to access class a.Applicable from class b.Test
    ... 1 more
</code></pre>

<p>I think it would make more sense if the lambda expression either worked just like the anonymous class or gave a compile-time error. So, I'm just wondering what is going on here.</p>

<hr>

<p>I tried removing the superinterface and declaring the method within <code>SomeApplicable</code> like this:</p>

<pre><code>package a;

@FunctionalInterface
public interface SomeApplicable {

    void apply(SomeApplicable self);
}
</code></pre>

<p>This obviously makes it work but allows us to see what's different in bytecode.</p>

<p>The synthetic <code>lambda$0</code> method compiled from the lambda expression seems identical in both cases, but I could spot one difference in the method arguments under bootstrap methods.</p>

<pre><code>Bootstrap methods:
  0 : # 58 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
        #59 (La/Applicable;)V
        #62 invokestatic b/Test.lambda$0:(La/SomeApplicable;)V
        #63 (La/SomeApplicable;)V
</code></pre>

<p>The <code>#59</code> changes from <code>(La/Applicable;)V</code> to <code>(La/SomeApplicable;)V</code>.</p>

<p>I don't really know how lambda metafactory works but I think this might be a key difference.</p>

<hr>

<p>I also tried explicitly declaring the <code>apply</code> method in <code>SomeApplicable</code> like this:</p>

<pre><code>package a;

@FunctionalInterface
public interface SomeApplicable extends Applicable&lt;SomeApplicable&gt; {

    @Override
    void apply(SomeApplicable self);
}
</code></pre>

<p>Now the method <code>apply(SomeApplicable)</code> actually exists and the compiler generates a bridge method for <code>apply(Applicable)</code>. Still the same error is thrown at runtime.</p>

<p>At bytecode level it now uses <code>LambdaMetafactory.altMetafactory</code> instead of <code>LambdaMetafactory.metafactory</code>:</p>

<pre><code>Bootstrap methods:
  0 : # 57 invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
    Method arguments:
        #58 (La/SomeApplicable;)V
        #61 invokestatic b/Test.lambda$0:(La/SomeApplicable;)V
        #62 (La/SomeApplicable;)V
        #63 4
        #64 1
        #66 (La/Applicable;)V
</code></pre>