JDK-8366848 : javac incorrectly allows calling interface static method via type variable
  • Type: CSR
  • Component: tools
  • Sub-Component: javac
  • Priority: P4
  • Status: Finalized
  • Resolution: Unresolved
  • Fix Versions: 26
  • Submitted: 2025-09-04
  • Updated: 2025-09-06
Related Reports
CSR :  
Description
Summary
-------

`javac` now rejects calling interface static methods through a type variable if the interface is the only upper bound of the type variable.

Problem
-------

`javac` incorrectly allowed interface static methods to be resolved against type variable if the interface is the only upper bound of the type variable.

JLS 4.4 and 4.9 together indicates that the members of such a type variable is a notional interface introduced with that only upper bound interface as its only direct superinterface. Meanwhile, JLS 9.4.1 (and 8.4.8) indicates static methods are never inherited from superinterfaces. In conclusion, such interface static methods are not present on such a type variable.

Currently in `javac`, for interface `java.util.Comparator<Object>`, and a static method `Comparator::reverseOrder`, these are the resolution behaviors:

- For type variable `T extends Comparator<Object>`, `T.reverseOrder()` succeeds;
- For type variable `T extends Object & Comparator<Object>`, `T.reverseOrder()` fails;
- For class `java.text.Collator` which has a direct superinterface `Comparator<Object>`, `Collator.reverseOrder()` fails;

Since `Collator` is a valid type argument for both previous type variables `T`, we should reject all interface static method resolution on type variables.

Solution
--------

Reject such interface static method resolutions in `javac` with a "cannot resolve" message for compiling against all previous releases, because the behavior in the example above applies for all releases.

Existing bytecode will continue to work.

Users can easily migrate by using the explicit interface identifier to resolve the static methods instead.

Specification
-------------

No change.

JLS 4.4:

> The members of a type variable X with bound T & I1 & ... & In are the members of the intersection type (ยง4.9) T & I1 & ... & In appearing at the point where the type variable is declared.

JLS 4.9:

>If Ck is Object, a notional interface is induced; otherwise, a notional class is induced with direct superclass type Ck. This class or interface has direct superinterface types T1', ..., Tn' and is declared in the package in which the intersection type appears.

> The members of an intersection type are the members of the class or interface it induces.

JLS 8.4.8:

> A class does not inherit `private` or `static` methods from its superinterface types.

JLS 9.4.1:

> An interface does not inherit `private` or `static` methods from its superinterfaces.

Comments
I have done a corpus compilation job against maven central artifacts and found no compilation failure due to this new restriction. Re-finalizing.
06-09-2025

Moving to Provisional, not Approved. Our default path to handling cases like this is to enforce the existing JLS rule against the current, latest release and _not_ start enforcing the rule against earlier releases. This aids uses in upgrading to the latest release if they are running with `javac --release $OLD` in their build systems. If there is a desire to also enforce this rule against older releases, some kind of corpus experiment should be done to gauge the frequency of this coding pattern.
04-09-2025