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

JDK 8 compile failure with Object targeting varargs T...

    XMLWordPrintable

    Details

    • Subcomponent:
    • CPU:
      x86_64
    • OS:
      linux

      Description

      FULL PRODUCT VERSION :
      java version "1.8.0"
      Java(TM) SE Runtime Environment (build 1.8.0-b127)
      Java HotSpot(TM) 64-Bit Server VM (build 25.0-b69, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Linux jtek 3.10.25-gentoo #6 SMP Sun Jan 5 14:08:51 PST 2014 x86_64 Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz GenuineIntel GNU/Linux


      A DESCRIPTION OF THE PROBLEM :
      I hit this bug while trying to get Gradle building under JDK8.

      I've created a simple reproduction of the issue here: https://bitbucket.org/marshallpierce/java8-varargs-generics-capture

      The README of that repo describes the issue, so I'll copy & paste it here for completeness.

      `GenericContainerWithVarargs<T>` has `add(T)` and `add(T...)`. This sample code (`WithVarargs`) that invokes `add(new Object())` compiles under Java 7, but doesn't under Java 8 M8 b127:
      ```
      GenericContainerWithVarargs<?> container = new GenericContainerWithVarargs<>();
      container.add(new Object());
      ```

       `GenericContainerWithoutVarargs` has only `add(T)`. This other sample code (`NoVarargs`) that also invokes `add(new Object())` doesn't compile under either version:
       ```
       GenericContainerWithoutVarargs<?> container = new GenericContainerWithoutVarargs<>();
       container.add(new Object());
       ```



      To reproduce this, try the following under both JDK 7 and JDK 8. There are two separate modules so that compile failures in one don't affect the other.
      ```
      ./gradlew clean :with-varargs:build
      ./gradlew clean :without-varargs:build
      ```

      Under JDK 7, `with-varargs` compiles (with an unchecked warning) but `without-varargs` does not:

      ```
      /.../without-varargs/src/main/java/withoutvarargs/GenericVarargs.java:6: error: method add in class GenericContainerWithoutVarargs<T> cannot be applied to given types;
              container.add(new Object());
                       ^
        required: CAP#1
        found: Object
        reason: actual argument Object cannot be converted to CAP#1 by method invocation conversion
        where T is a type-variable:
          T extends Object declared in class GenericContainerWithoutVarargs
        where CAP#1 is a fresh type-variable:
          CAP#1 extends Object from capture of ?
      1 error
      ```

      Under JDK 8 M8 b127, neither builds.

      `with-varargs`:

      ```
      /.../with-varargs/src/main/java/withvarargs/GenericContainerWithVarargs.java:9: warning: [unchecked] Possible heap pollution from parameterized vararg type T
          void add(T... objects) {
                        ^
        where T is a type-variable:
          T extends Object declared in class GenericContainerWithVarargs
      /.../with-varargs/src/main/java/withvarargs/GenericVarargs.java:6: error: no suitable method found for add(Object)
              container.add(new Object());
                       ^
          method GenericContainerWithVarargs.add(CAP#1) is not applicable
            (argument mismatch; Object cannot be converted to CAP#1)
          method GenericContainerWithVarargs.add(CAP#1...) is not applicable
            (varargs mismatch; Object cannot be converted to CAP#1)
        where CAP#1 is a fresh type-variable:
          CAP#1 extends Object from capture of ?
      1 error
      1 warning
      ```

      `without-varargs`:
      ```
      /.../without-varargs/src/main/java/withoutvarargs/GenericVarargs.java:6: error: method add in class GenericContainerWithoutVarargs<T> cannot be applied to given types;
              container.add(new Object());
                       ^
        required: CAP#1
        found: Object
        reason: argument mismatch; Object cannot be converted to CAP#1
        where T is a type-variable:
          T extends Object declared in class GenericContainerWithoutVarargs
        where CAP#1 is a fresh type-variable:
          CAP#1 extends Object from capture of ?
      1 error
      ```

      This is a simplified version of this code in Gradle's [DefaultModelRegistry](https://github.com/gradle/gradle/blob/75785398f19b634494316b0eb8f2427ab6adbc1a/subprojects/core/src/main/groovy/org/gradle/model/internal/DefaultModelRegistry.java#L210) that has an analogous failure:
      ```
      private Inputs toInputs(Iterable<ModelPath> inputPaths) {
          ImmutableList.Builder<?> builder = ImmutableList.builder();
          for (ModelPath inputPath : inputPaths) {
              builder.add(getClosedModel(inputPath));
          }
          return new DefaultInputs(builder.build());
      }
      ```

      The Guava ImmutableList.Builder that it's using basically has the `with-varargs` case: both `add(E e)` and `add(E... es)` are provided, so it compiled under Java 7 and now doesn't.


      REGRESSION. Last worked in version 7u51

      ADDITIONAL REGRESSION INFORMATION:
      java version "1.8.0"
      Java(TM) SE Runtime Environment (build 1.8.0-b127)
      Java HotSpot(TM) 64-Bit Server VM (build 25.0-b69, mixed mode)


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Clone the sample repo https://bitbucket.org/marshallpierce/java8-varargs-generics-capture

      2. Under java 7, run:
      ./gradlew clean :with-varargs:build
      See that it compiles.

      3. Under java 8, run the same command and see that it fails.

      4. For contrast, note that doing the same for :without-varargs fails for both versions.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The JDK8 compiler should behave like the JDK7 one.

      Unless the JDK7 one was wrong all along? In which case it'd be great if the JDK7 compiler also failed (perhaps in a subsequent JDK7 update).
      ACTUAL -
      The JDK8 compiler rejects code that the JDK7 compiler accepted.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      There's already a minimal test case at https://bitbucket.org/marshallpierce/java8-varargs-generics-capture but here are the classes contained there.

      class GenericContainerWithVarargs<T> {

          void add(T obj) {

          }

          void add(T... objects) {

          }

      }

      class WithVarargs {
          private void foo() {
              GenericContainerWithVarargs<?> container = new GenericContainerWithVarargs<>();
              container.add(new Object());
          }
      }

      class GenericContainerWithoutVarargs<T> {

          void add(T obj) {

          }

      }

      class NoVarargs {
          private void foo() {
              GenericContainerWithoutVarargs<?> container = new GenericContainerWithoutVarargs<>();
              container.add(new Object());
          }
      }

      ---------- END SOURCE ----------

        Attachments

          Activity

            People

            Assignee:
            vromero Vicente Arturo Romero Zaldivar
            Reporter:
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: