-
Bug
-
Resolution: Not an Issue
-
P4
-
8, 11, 17, 21, 23
ADDITIONAL SYSTEM INFORMATION :
Works in:
* oraclejdk1.7.0_40
Fails in:
* oraclejdk1.8.0_77
* oraclejdk1.8.0_301
* openjdk-11.0.2
* openjdk-17.0.1
* temurinjdk-21.0.2+13
* openjdk-23-ea+14
A DESCRIPTION OF THE PROBLEM :
The following Code compiles in Javac 7 and Eclipsec, but not in Javac 8 or higher:
```java
public class Reproducer {
public static void main(String[] args) {
B<?> instance = new B<>();
m(instance);
}
static <G> void m(A<G> instance) {
System.out.println(instance);
}
static void m(B<?> instance) {
System.out.println(instance);
}
interface A<G> {}
static class B<G> implements A<G> {}
}
```
The compiler error:
```
Reproducer.java:4: error: reference to m is ambiguous
m(instance);
^
both method <G>m(A<G>) in Reproducer and method m(B<?>) in Reproducer match
where G is a type-variable:
G extends Object declared in method <G>m(A<G>)
1 error
```
If you remove the method `m(B<?>)` then the code compiles and a type of `B<?>` is passed to the method `m(A<G>)`.
So if you consider the informal intuition given in JLS 15.12.2.5. Choosing the Most Specific Method (https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.12.2.5) then this code should clearly compile:
> The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
Also if you change `m(B<?>)` to the following then the code also compiles:
```java
static <G> void m(B<G> instance) {
System.out.println(instance);
}
```
From my understanding of JLS 18.5.4. More Specific Method Inference (https://docs.oracle.com/javase/specs/jls/se21/html/jls-18.html#jls-18.5.4) the methods `m(B<?>)` and `m(B<G>)` should be identical for the purpose of overload resolution. The process is indifferent to the more specific method m1 being generic. It is even made clear that:
> Even if m1 is generic, the type parameters of m1 are treated as type variables, not inference variables.
This may be related to https://bugs.openjdk.org/browse/JDK-8325859, but that bug does not appear to be present in Javac 8
Note that I set "Previously worked in the Release" to "8 update releases", even though this issue is present in Javac 8. That is because I was not allowed to select Java 7, but still wanted to make sure this is recognized as a regression.
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
echo "public class Reproducer {
public static void main(String[] args) {
B<?> instance = new B<>();
m(instance);
}
static <G> void m(A<G> instance) {
System.out.println(instance);
}
static void m(B<?> instance) {
System.out.println(instance);
}
interface A<G> {}
static class B<G> implements A<G> {}
}
" > Reproducer.java
javac Reproducer.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code compiles and the main method invokes the overload `m(B<?>)`.
ACTUAL -
Reproducer.java:4: error: reference to m is ambiguous
m(instance);
^
both method <G>m(A<G>) in Reproducer and method m(B<?>) in Reproducer match
where G is a type-variable:
G extends Object declared in method <G>m(A<G>)
1 error
CUSTOMER SUBMITTED WORKAROUND :
Use a generic type parameter instead of a wildcard. For example instead of
```java
static void m(B<?> instance) {
System.out.println(instance);
}
```
you can write the following to bypass the error:
```java
static <G> void m(B<G> instance) {
System.out.println(instance);
}
```
FREQUENCY : always
Works in:
* oraclejdk1.7.0_40
Fails in:
* oraclejdk1.8.0_77
* oraclejdk1.8.0_301
* openjdk-11.0.2
* openjdk-17.0.1
* temurinjdk-21.0.2+13
* openjdk-23-ea+14
A DESCRIPTION OF THE PROBLEM :
The following Code compiles in Javac 7 and Eclipsec, but not in Javac 8 or higher:
```java
public class Reproducer {
public static void main(String[] args) {
B<?> instance = new B<>();
m(instance);
}
static <G> void m(A<G> instance) {
System.out.println(instance);
}
static void m(B<?> instance) {
System.out.println(instance);
}
interface A<G> {}
static class B<G> implements A<G> {}
}
```
The compiler error:
```
Reproducer.java:4: error: reference to m is ambiguous
m(instance);
^
both method <G>m(A<G>) in Reproducer and method m(B<?>) in Reproducer match
where G is a type-variable:
G extends Object declared in method <G>m(A<G>)
1 error
```
If you remove the method `m(B<?>)` then the code compiles and a type of `B<?>` is passed to the method `m(A<G>)`.
So if you consider the informal intuition given in JLS 15.12.2.5. Choosing the Most Specific Method (https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.12.2.5) then this code should clearly compile:
> The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
Also if you change `m(B<?>)` to the following then the code also compiles:
```java
static <G> void m(B<G> instance) {
System.out.println(instance);
}
```
From my understanding of JLS 18.5.4. More Specific Method Inference (https://docs.oracle.com/javase/specs/jls/se21/html/jls-18.html#jls-18.5.4) the methods `m(B<?>)` and `m(B<G>)` should be identical for the purpose of overload resolution. The process is indifferent to the more specific method m1 being generic. It is even made clear that:
> Even if m1 is generic, the type parameters of m1 are treated as type variables, not inference variables.
This may be related to https://bugs.openjdk.org/browse/JDK-8325859, but that bug does not appear to be present in Javac 8
Note that I set "Previously worked in the Release" to "8 update releases", even though this issue is present in Javac 8. That is because I was not allowed to select Java 7, but still wanted to make sure this is recognized as a regression.
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
echo "public class Reproducer {
public static void main(String[] args) {
B<?> instance = new B<>();
m(instance);
}
static <G> void m(A<G> instance) {
System.out.println(instance);
}
static void m(B<?> instance) {
System.out.println(instance);
}
interface A<G> {}
static class B<G> implements A<G> {}
}
" > Reproducer.java
javac Reproducer.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code compiles and the main method invokes the overload `m(B<?>)`.
ACTUAL -
Reproducer.java:4: error: reference to m is ambiguous
m(instance);
^
both method <G>m(A<G>) in Reproducer and method m(B<?>) in Reproducer match
where G is a type-variable:
G extends Object declared in method <G>m(A<G>)
1 error
CUSTOMER SUBMITTED WORKAROUND :
Use a generic type parameter instead of a wildcard. For example instead of
```java
static void m(B<?> instance) {
System.out.println(instance);
}
```
you can write the following to bypass the error:
```java
static <G> void m(B<G> instance) {
System.out.println(instance);
}
```
FREQUENCY : always