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

Strange compilation error on calling map and get on Optional of raw type parameter

XMLWordPrintable

    • x86_64
    • linux

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


      ADDITIONAL OS VERSION INFORMATION :
      Linux 4.4.0-66-generic #87-Ubuntu SMP Fri Mar 3 15:29:05 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux


      A DESCRIPTION OF THE PROBLEM :
      The following code does not compile:

      import java.util.Optional;

      class B<T> {}

      public class Test {
      static B<Integer> fn(B<Object> a) { return null; }

      public static void main(String[] args) {

                      Optional<B> opt = Optional.empty(); // note raw type parameter B

                      B<Integer> res = opt.map(Test::fn).get(); // COMPILE ERROR: incompatible types: Object cannot be converted to B<Integer>

      }
      }

      It looks like javac infers the result of opt.map(Test::fn) to be Optional<Object> instead of Optional<B<Integer>>. I expected it to be inferred as Optional<B<Integer>> because fn returns B<Integer>.

      Also, it's curious that the program does compile if we explicitly cast the result of opt.map as follows:

      B<Integer> res = ((Optional<B<Integer>>) opt.map(Test::fn)).get();

      It also compiles successfully if we make fn take a raw B, instead of B<Object>.

      If the signature of fn is erased because of unchecked conversion, shouldn't the erasure return a raw B? Does the compiler erase the return to Object, or why does the compilation fail?


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile the program shown below

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Expected program to compile successfully
      ACTUAL -
      Compilation error

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Compilation error: incompatible types: Object cannot be converted to B<Integer>

      REPRODUCIBILITY :
      This bug can be reproduced always.

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

      class B<T> {}

      public class Test {
      static B<Integer> fn(B<Object> a) { return null; }

      public static void main(String[] args) {

                      Optional<B> opt = Optional.empty(); // note raw type parameter B

                      B<Integer> res = opt.map(Test::fn).get(); // COMPILE ERROR: incompatible types: Object cannot be converted to B<Integer>

      }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      Multiple workarounds:

      0) Don't use raw types in the first place

      1) declare fn() as: static B<Integer> fn(B a) { return null; } // NOTE: parameter is raw B instead of B<Object>

      2) explicit cast: B<Integer> res = ((Optional<B<Integer>>) opt.map(Test::fn)).get();


        1. Test.java
          0.4 kB
          Fairoz Matte

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: