On Tue, 21 Feb 2023 01:42:41 GMT, Archie L. Cobbs <d...@openjdk.org> wrote:
>> This bug relates to the "potentially ambiguous overload" warning which is >> enabled by `-Xlint:overloads`. >> >> The warning detects certain ambiguities that can cause problems for lambdas. >> For example, consider the interface `Spliterator.OfInt`, which declares >> these two methods: >> >> void forEachRemaining(Consumer<? super Integer> action); >> void forEachRemaining(IntConsumer action); >> >> Both methods have the same name, same number of parameters, and take a >> lambda with the same "shape" in the same argument position. This causes an >> ambiguity in any code that wants to do this: >> >> spliterator.forEachRemaining(x -> { ... }); >> >> That code won't compile; instead, you'll get this error: >> >> Ambiguity.java:4: error: reference to forEachRemaining is ambiguous >> spliterator.forEachRemaining(x -> { }); >> ^ >> both method forEachRemaining(IntConsumer) in OfInt and method >> forEachRemaining(Consumer<? super Integer>) in OfInt match >> >> >> The problem reported by the bug is that the warning fails to detect >> ambiguities which are created purely by inheritance, for example: >> >> interface ConsumerOfInteger { >> void foo(Consumer<Integer> c); >> } >> >> interface IntegerConsumer { >> void foo(IntConsumer c); >> } >> >> // We should get a warning here... >> interface Test extends ConsumerOfInteger, IntegerConsumer { >> } >> >> >> The cause of the bug is that ambiguities are detected on a per-method basis, >> by checking whether a method is part of an ambiguity pair when we visit that >> method. So if the methods in an ambiguity pair are inherited from two >> distinct supertypes, we'll miss the ambiguity. >> >> To fix the problem, we need to look for ambiguities on a per-class level, >> checking all pairs of methods. However, it's not that simple - we only want >> to "blame" a class when that class itself, and not some supertype, is >> responsible for creating the ambiguity. For example, any interface extending >> `Spliterator.OfInt` will automatically inherit the two ambiguities mentioned >> above, but these are not the interface's fault so to speak so no warning >> should be generated. Making things more complicated is the fact that methods >> can be overridden and declared in generic classes so they only conflict in >> some subtypes, etc. >> >> So we generate the warning when there are two methods m1 and m2 in a class C >> such that: >> >> * m1 and m2 consitiute a "potentially ambiguous overload" (using the same >> definition as before) >> * There is no direct supertype T of C such that m1 and m2, or some methods >> they override, both exist in T and constitute a "potentially ambiguous >> overload" as members of T >> * We haven't already generated a warning for either m1 or m2 in class C >> >> If either method is declared in C, we locate the warning there, but when >> both methods are inherited, there's no method declaration to point at so the >> warning is instead located at the class declaration. >> >> I noticed a couple of other minor bugs; these are also being fixed here: >> >> (1) For inherited methods, the method signatures were being reported as they >> are declared, rather than in the context of the class being visited. As a >> result, when a methods is inherited from a generic supertype, the ambiguity >> is less clear. Here's an example: >> >> interface Upper<T> { >> void foo(T c); >> } >> >> interface Lower extends Upper<IntConsumer> { >> void foo(Consumer<Integer> c); >> } >> >> Currently, the error is reported as: >> >> warning: [overloads] foo(Consumer<Integer>) in Lower is potentially >> ambiguous with foo(T) in Upper >> >> Reporting the method signatures in the context of the class being visited >> makes the ambiguity clearer: >> >> warning: [overloads] foo(Consumer<Integer>) in Lower is potentially >> ambiguous with foo(IntConsumer) in Upper >> >> >> (2) When a method is identified as part of an ambiguous pair, we were >> setting a `POTENTIALLY_AMBIGUOUS` flag on it. This caused it to be forever >> excluded from future warnings. For methods that are declared in the class >> we're visiting, this makes sense, but it doesn't make sense for inherited >> methods, because it disqualifies them from participating in the analysis of >> any other class that also inherits them. >> >> As a result, for a class like the one below, the compiler was only >> generating one warning instead of three: >> >> public interface SuperIface { >> void foo(Consumer<Integer> c); >> } >> >> public interface I1 extends SuperIface { >> void foo(IntConsumer c); // warning was generated here >> } >> >> public interface I2 extends SuperIface { >> void foo(IntConsumer c); // no warning was generated here >> } >> >> public interface I3 extends SuperIface { >> void foo(IntConsumer c); // no warning was generated here >> } >> >> >> With this patch the `POTENTIALLY_AMBIGUOUS` flag is no longer needed. I >> wasn't sure whether to renumber all the subsequent flags, or just leave an >> empty placeholder, so I chose the latter. >> >> Finally, this fix uncovers new warnings in `java.base` and `java.desktop`, >> so these are now suppressed in the patch. > > Archie L. Cobbs has updated the pull request incrementally with one > additional commit since the last revision: > > Remove @SuppressWarnings("overloads") annotations that were added but not > needed. I think a CSR is needed as we will be generating more warnings and projects compiling with -Werror could see compilation errors ------------- PR: https://git.openjdk.org/jdk/pull/12645