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

javac with '-source 7' should honor default methods in implemented Java 8 interfaces

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P3 P3
    • None
    • 8, 11, 17
    • tools
    • Cause Known
    • 8
    • generic
    • generic

      Reported by Richard Hernandez (riher@amazon.com).

      Consider the following example:

      ```
      interface A {
        void foo();
      }
      ```

      ```
      interface B extends A {
        @Override default void foo() { }
      }
      ```

      ```
      class C implements B { }
      ```

      If we compile `A.java` and `B.java` with `javac -source 8` and `C.java` with `-source 7` we will get the following error:
      ```
      $ javac -source 8 A.java
      $ javac -source 8 B.java
      $ javac -source 7 C.java
      C.java:1: error: C is not abstract and does not override abstract method foo() in A
      class C implements B { }
      ```

      I think this is wrong, because `foo()` is implemented as a default method in `B`.

      The following, slightly simpler example works perfectly fine, although it also depends on a default method in an implemented interface:

      ```
      interface D {
        default void bar() { }
      }
      ```

      ```
      class E implements D { }
      ```

      ```
      $ javac -source 8 D.java
      $ javac -source 7 E.java
      ```

      In the second example, `javac` happily accepts the default implementation of `bar()` from interface `D`.

      Interestingly, `ecj` (the [Eclipse Compiler for Java](https://ftp.fau.de/eclipse/eclipse/downloads/drops4/R-4.27-202303020300/ecj-4.27.jar)) compiles both examples without any errors:

      ```
      $ java -jar ecj-4.27.jar -cp . -source 8 A.java
      $ java -jar ecj-4.27.jar -cp . -source 8 B.java
      $ java -jar ecj-4.27.jar -cp . -source 7 C.java
      ```

      I think the problem is in [`com.sun.tools.javac.code.Types::firstUnimplementedAbstractImpl()`](https://github.com/openjdk/jdk17u/blob/22cdf79dce8b2ec7c68e3ba71550d70e4eeb2c48/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java#L3110-L3129), specifically in line 3123:

      ```
      3123: if (allowDefaultMethods) {
      3124: MethodSymbol prov = interfaceCandidates(impl.type, absmeth).head;
      3125: if (prov != null && prov.overrides(absmeth, impl, this, true)) {
      3126: implmeth = prov;
      3127: }
      3128 }
      ```

      Here the check for imlementations of `A::foo()` (`absmeth` in the code snippet above) for class `C` (`impl` in the code snippet above) will only be performed if `allowDefaultMethods` is set to true, but `allowDefaultMethods` is globally set to false by `-source 7`.

      Instead of relying on the *global* `-source` setting, I think `firstUnimplementedAbstractImpl()` should rather rely on the class file version of the corresponing class (i.e. `B` in this case) and if that class file version is >= 8, it should consider its default method implementations. I even think that the check for `allowDefaultMethods` could be completely removed, because if the class dependency `B` wasn't compiled before, it will be compiled from source and fail for `-source 7` because it contains a default method. If on the other hand, the class dependency `B` was already compiled to a class file with `-source 8` it is OK to use it's default method.

      I know that support for `-source 7` was removed in JDK 20 (by JDK-8173605), but this issue appears in all JDKs from 8 to 19. I still think that fixing it in 8, 11 & 17 might be useful, because there are use cases where real world projects migrate to 8, 11 or 17 but still need to compile some source files with `-source -7` (at least temporary, until all their dependencies like bytecode manipulation libraries have been updated).

            simonis Volker Simonis
            simonis Volker Simonis
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: