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

javac does not handle "notional functional interface" types correctly

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Cannot Reproduce
    • Icon: P4 P4
    • None
    • 8, 9, 10, 11
    • tools
    • generic
    • generic

      FULL PRODUCT VERSION :
      All versions of Java 8 to 10ea

      A DESCRIPTION OF THE PROBLEM :
      JLS§9.8. states that a functional interface type may be "An intersection type (§4.9) that induces a notional functional interface". While it considers the case of combining a declared functional interface with a marker interface as "typical", it does not mandate it. In contrast, javac searches the intersection type for a declared functional interface and rejects it as target type for lambda expressions or method references when it doesn't find one.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Try to compile the following code

          interface S {
              void method1();
          }
          interface I1 extends S {
              void method2();
          }
          interface I2 extends S {
              @Override default void method1() {}
          }
          Object p = (I1&I2)() -> {};
          Object q = (S&I1&I2)() -> {};


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      This could should compile without errors. It should not matter whether "(I1 & I2)" or "(S & I1 & I2)" has been used, as "S" is redundant here.
      ACTUAL -
      javac rejects "(I1 & I2)" as target type of a lambda expression because it doesn't find a declared functional interface in the explicitly specified types of the intersection type while it accept "(S & I1 & I2)" because it finds one.

      Note that "S" is a declared functional interface in the example to demonstrate the inconsistency. It actually doesn't have to be a functional interface, i.e. it could have more than one abstract method with "I2" having default methods for all of them. Then "(I1 & I2)" should still be a notional functional interface type, as it has only one abstract method.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Bug.java:11: error: incompatible types: I1 is not a functional interface
          Object p = (I1&I2)() -> {};
                            ^
          multiple non-overriding abstract methods found in interface I1
      1 error

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      class Bug {
          interface S {
              void method1();
          }
          interface I1 extends S {
              void method2();
          }
          interface I2 extends S {
              @Override default void method1() {}
          }
          Object p = (I1&I2)() -> {};
          Object q = (S&I1&I2)() -> {};
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Insert the redundant super interface, if there is a super interface that is a functional interface. Otherwise, add another interface extending all interfaces of the intersection type, to take the place of the notional functional interface, i.e. "interface NotSoNotional extends I1,I2 {}".

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

              Created:
              Updated:
              Resolved: