RFR: 5059679: name clash not reported for interface inheritance

Remi Forax forax at univ-mlv.fr
Thu Feb 9 21:58:08 UTC 2023



----- Original Message -----
> From: "Archie L. Cobbs" <duke at openjdk.org>
> To: "compiler-dev" <compiler-dev at openjdk.org>
> Sent: Thursday, February 9, 2023 10:07:32 PM
> Subject: RFR: 5059679: name clash not reported for interface inheritance

> Consider this input:
> 
> public class NarrowingNameClash {
> 
>    public interface Upper<T> {
>        void method(T param);
>    }
> 
>    public interface Lower<R> extends Upper<Class<R>> {
>        void method(Class<?> param);        // erasure name clash here
>    }
> }
> 
> This violates §8.4.8.3 because `method(Class<R>)` and `method(Class<?>)` have
> the same erasure. However, the compiler is not reporting an error in this case.
> 
> Here's my understanding of the bug... (reviewer please double-check this :)

It's maybe a spec bug because you can still have a raw class that implement both interfaces.
(if the class is raw, all the hierarchy is raw so you can implement Lower and Upper (both raw classes) at the same time).

Something like

  class Foo implements Upper, Lower {
    void m(Object o) { ... }
    void m(Class c) { ... }
  }

Rémi


> 
> §8.4.8.3 "Requirements in Overriding and Hiding" says:
> 
> It is a compile-time error if a class or interface C has a member method m1 and
> there exists a method m2 declared in C or a superclass or superinterface of C,
> A, such that all of the following are true:
> 
> * m1 and m2 have the same name.
> * m2 is accessible (§6.6) from C.
> * The signature of m1 is not a subsignature (§8.4.2) of the signature of m2 as a
> member of the supertype of C that names A.
> * The declared signature of m1 or some method m1 overrides (directly or
> indirectly) has the same erasure as the declared signature of m2 or some method
> m2 overrides (directly or indirectly).
> 
> Method `method(Class<R>)` is inherited by `Lower` from `Upper` and is therefore
> a member of `Lower`. Note that upon inheritance its parameter `T` is
> reinterpreted as `Class<R>` in the context of `Lower`'s generic
> parameterization.
> 
> Let C = `Lower`, A = `Upper`, m1 = `method(Class<R>)` and m2 =
> `method(Class<?>)`.
> 
> The compiler is comparing the erasures of `method(T)`, which is "some method m1
> overrides", and m2 = `method(Class<?>)`, and these are different, so no bug is
> reported.
> 
> That comparison is appropriate, however, what it also needs to do is compare the
> erasures of m1 and m2, which are both `method(Class)`.
> 
> In a nutshell: within the context of `Lower`, the method `method(Class<R>)`
> inherited from `Upper`, when erased, has a different signature from its
> original form `method(T)` in `Upper`, when erased. The possibility of this
> different form was not being taken into account in the compiler.
> 
> -------------
> 
> Commit messages:
> - Fix bug where certain erasure name clashes were not being detected.
> 
> Changes: https://git.openjdk.org/jdk/pull/12503/files
> Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=12503&range=00
>  Issue: https://bugs.openjdk.org/browse/JDK-5059679
>  Stats: 23 lines in 3 files changed: 22 ins; 0 del; 1 mod
>  Patch: https://git.openjdk.org/jdk/pull/12503.diff
>  Fetch: git fetch https://git.openjdk.org/jdk pull/12503/head:pull/12503
> 
> PR: https://git.openjdk.org/jdk/pull/12503


More information about the compiler-dev mailing list