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

Unexpected error compiling generic stream() code in JDK 19 (but works in JDK 8)

XMLWordPrintable

    • 9
    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      JDK 19:
      java version "19.0.2" 2023-01-17
      Java(TM) SE Runtime Environment (build 19.0.2+7-44)
      Java HotSpot(TM) 64-Bit Server VM (build 19.0.2+7-44, mixed mode, sharing)


      A DESCRIPTION OF THE PROBLEM :
      Hello,

      While updating a large code base
      I encountered a compilation error
      in JDK 19
      which does not happen in JDK 8.

      I eventually managed to reproduce it
      in the test code below.

      JDK 8 compiles the code OK.

      JDK 19 produces the following error:

          error: getContext() in AbstractSomething cannot implement getContext() in Something
            return type CAP#1 is not compatible with CAP#2
            where Ctx#1,Ctx#2 are type-variables:
              Ctx#1 extends Context declared in class AbstractSomething
              Ctx#2 extends Context declared in interface Something
            where CAP#1,CAP#2 are fresh type-variables:
              CAP#1 extends Context from capture of ? extends Context
              CAP#2 extends Context from capture of ? extends Context
          1 error

      The error does not include any source filenames or line numbers.

      The error suggests that something is wrong in the AbstractSomething class
      but the actual cause of the problem
      seems to be the generics of the stream() code in the getSomethings() method
      which is not mentioned in the error.

      JDK 19 will compile the code
      after replacing .map(c -> construct(c))
      with .map(this::construct)

      JDK 8 compiles either version of the code.

      This feels like a regression in the compiler
      but maybe I am missing something?


      REGRESSION : Last worked in version 8u361

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Compile the test code using JDK 8
      2. Code compiles OK
      3. Compile the test code using JDK 19
      4. An unexpected error is produced


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The code is expected to compile JDK 19

      ACTUAL -
      Error message produced by JDK 19:

          error: getContext() in AbstractSomething cannot implement getContext() in Something
            return type CAP#1 is not compatible with CAP#2
            where Ctx#1,Ctx#2 are type-variables:
              Ctx#1 extends Context declared in class AbstractSomething
              Ctx#2 extends Context declared in interface Something
            where CAP#1,CAP#2 are fresh type-variables:
              CAP#1 extends Context from capture of ? extends Context
              CAP#2 extends Context from capture of ? extends Context
          1 error


      ---------- BEGIN SOURCE ----------
      import java.util.List;
      import java.util.stream.Collectors;
      import java.util.stream.Stream;

      public class Test {

          List<Something> getSomethings() {
              return Stream.of(
                              SomethingA.class,
                              SomethingB.class)
                      .map(c -> construct(c)) // UNEXPECTED COMPILER ERROR IN JDK 17+19 (BUT COMPILES IN JDK 8)
                      // .map(this::construct) // COMPILES IN JDK 17+19+8
                      .collect(Collectors.toList());
          }

          Something construct(Class<? extends Something> clazz) {
              return null;
          }

          interface Context { }
          interface ContextA extends Context { }
          interface ContextB extends Context { }

          interface Something<Ctx extends Context> {
              Ctx getContext();
          }

          interface SpecificSomething<Ctx extends Context>
                  extends Something<Ctx> { }

          abstract static class AbstractSomething<Ctx extends Context>
                  implements Something<Ctx> {

              @Override
              public Ctx getContext() {
                  return null;
              }
          }

          static class SomethingA
                  extends AbstractSomething<ContextA>
                  implements SpecificSomething<ContextA> { }

          static class SomethingB
                  extends AbstractSomething<ContextB>
                  implements SpecificSomething<ContextB> { }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      JDK 19 will compile the code
      after replacing .map(c -> construct(c))
      with .map(this::construct)


      FREQUENCY : always


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

              Created:
              Updated: