JDK-8147546 : regression when type-checking generic calls inside nested declarations occurring in method context
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 9
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2016-01-18
  • Updated: 2016-02-01
  • Resolved: 2016-01-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b103Fixed
Related Reports
Relates :  
Description
The following example fails to compile:

abstract class Test {

  interface I<O> { void t(O clazz); }
  abstract <A> I<A> a(Class<A> clazz);
  abstract <B> B b(Class<B> t);
  abstract <C> C c(C a);

  Object f(Iterable<Object> xs) {
    return c(c(new Object() {
      <T> void g(Class<T> clazz) {
        a(clazz).t(b(clazz));
      }
    }));
  }
}

Test.java:11: error: method t in interface I<O> cannot be applied to given types;
        a(clazz).t(b(clazz));
                ^
  required: T#1
  found: T#1
  reason: argument mismatch; inference variable B has incompatible bounds
      equality constraints: T#2
      upper bounds: T#1,Object
  where T#1,O,B,T#2 are type-variables:
    T#1 extends Object declared in method <T#1>g(Class<T#1>)
    O extends Object declared in interface I
    B extends Object declared in method <B>b(Class<B>)
    T#2 extends Object declared in method <T#2>g(Class<T#2>)
Comments
When dropping speculative class declarations (DeferredAttr.unenterScanner) we should also drop related entries from the ArgumentAttr cache.
18-01-2016

The problem has to do with the fact that the method declaration introducing the variable <T> is nested inside a method context; when speculative attribution will kick in, the class decl will be checked speculatively, and then then class will be thrown away afterwards; this means that ArgumentAttr will be caching results of a temporary class declaration - thus yielding in potentially spurious constraints being saved. The problem is also reproducible with the following code using lambdas: abstract class Test { interface I<O> { void t(O clazz); } abstract <B> B b(Class<B> t); abstract <C> C c(C a); abstract Object d(Runnable r); Object f(Iterable<Object> xs) { return c(d( () -> { class Foo { <T> void g(Class<T> clazz, I<T> i) { i.t(b(clazz)); } } })); } }
18-01-2016