Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8051807

JLS 15.12.2.7: Generic type inference fails with once-removed interface impl

XMLWordPrintable

    • x86
    • windows_8

      FULL PRODUCT VERSION :
      java version "1.7.0_65"
      Java(TM) SE Runtime Environment (build 1.7.0_65-b19)
      Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Windows 8 64-bit: Microsoft Windows [Version 6.2.9200]

      Originally discovered on Ubuntu, JDK 7u45 (box not accessible at the time)

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      Nothing relevant (pure compiler bug)

      A DESCRIPTION OF THE PROBLEM :
      The generic type inference seems to break down in the example code below. When a class is declared as generic with a bound on the type parameter and also implements an interface with the same parameter, the bound should also apply to the interface. Succinctly, if class C<T extend B> implements I2<T>, then C<?> should be assignable to I2<? extends B>, since the parameter is known by definition to extend B. Naturally, if I2<T> extends I1<T> as well, then C<?> should be assignable to I1<? extends B>.

      The compiler inference does work for this case (as evidenced by the test3() call), but seems to break down when this exact case occurs in a generic type parameter instead. In particular, the compiler fails to verify that List<C<?>> is a subtype of List<? extends I1<? extends B>> during method invocation conversion. Oddly enough, the compiler is okay with the conversion through an intermediate type List<? extends I2<? extends B>>, which is correct, but seems to limit an arbitrary bound on the supertype type-search.

      Linked original discussion: http://stackoverflow.com/questions/24817306/java-bounded-generics-type-inference-bug-method-invocation-jls-15-12-2-7

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile the following code with

      javac Main.java

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The code compiles correctly.
      ACTUAL -
      The compilation fails with the error below.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Main.java:12: error: method test2 in class Main cannot be applied to given types;
              test2((List<BoundedI2<?>>) null);
              ^
        required: List<? extends Interface1<? extends Bound>>
        found: List<BoundedI2<?>>
        reason: actual argument List<BoundedI2<?>> cannot be converted to List<? extends Interface1<? extends Bound>> by method invocation conversion
      1 error

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.util.List;

      public class Main {
          interface Interface1<T> {}
          interface Interface2<T> extends Interface1<T> {}
          static class Bound {}
          interface BoundedI1<T extends Bound> extends Interface1<T> {}
          interface BoundedI2<T extends Bound> extends Interface2<T> {}

          public static void main(String[] args) {
              test((List<BoundedI2<?>>) null);
              test2((List<BoundedI2<?>>) null);
              test3((BoundedI2<?>) null);
          }

          public static void test(List<? extends Interface2<? extends Bound>> list) { test2(list); }
          public static void test2(List<? extends Interface1<? extends Bound>> list) {}
          public static void test3(Interface1<? extends Bound> instance) {}
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      The compiler is okay if the type BoundedI2<?> is declared with the redundant bound specification BoundedI2<? extends Bound>, though the latter adds quite a bit of unnecessary verbosity if the type is widely used and if the bound in question is nontrivial to specify.

            dlsmith Dan Smith
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: