Home » Language IDEs » Java Development Tools (JDT) » ECJ error in overload resolution, but not with javac
ECJ error in overload resolution, but not with javac [message #1769977] |
Mon, 07 August 2017 09:04 |
Jens Auer Messages: 11 Registered: February 2017 |
Junior Member |
|
|
I have some code which compiles with Javac 8 and 9, but not with ecj in Eclipse. I am writing some utility functions for Optional and the specializations for primitive types, and while doing this wrote two functions
package sandbox;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
public class Test {
static class OptionalUtils {
public static <T> OptionalInt map(Optional<T> o, ToIntFunction<? super T> f) {
if (o.isPresent()) {
return OptionalInt.of(f.applyAsInt(o.get()));
} else {
return OptionalInt.empty();
}
}
public static <T> OptionalDouble map(Optional<T> o, ToDoubleFunction<? super T> f) {
if (o.isPresent()) {
return OptionalDouble.of(f.applyAsDouble(o.get()));
} else {
return OptionalDouble.empty();
}
}
}
private static int double2int(double x) {
return 2;
}
public static void main(String[] args) {
Optional<Double> oEmpty = Optional.empty();
OptionalUtils.map(oEmpty, Test::double2int);
}
}
}
The call to OptionalUtils.map is flagged with an error:
Quote:
Description Resource Path Location Type
The method map(Optional<Double>, ToIntFunction<? super Double>) is ambiguous for the type Test.OptionalUtils Test.java /Playground/src/sandbox line 34 Java Problem
This is independent from Optional because the following modified example produces the same error, but compiles with javac:
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
public class Test {
static class Generic<T> {
}
public static <T> String map(Generic<T> o, ToIntFunction<? super T> f) {
return null;
}
public static <T> Number map(Generic<T> o, ToDoubleFunction<? super T> f) {
return null;
}
private static int double2int(double x) {
return 2;
}
public static void main(String[] args) {
Generic<Double> oEmpty = new Generic<>();
map(oEmpty, Test::double2int);
}
}
double2int is assignable to both ToIntFunction and ToDoubleFunction, so intuitively I can see why it is ambiguous. I am not really familiar with the details of overload resolution in Java, but since calling the overload with ToDoubleFunction involves a conversion, I would expect that the better match is the other overload and it is preferred.
Best wishes,
Jens
[Updated on: Mon, 07 August 2017 12:04] Report message to a moderator
|
|
| |
Re: ECJ error in overload resolution, but not with javac [message #1771456 is a reply to message #1770997] |
Fri, 25 August 2017 08:36 |
Jens Auer Messages: 11 Registered: February 2017 |
Junior Member |
|
|
Hi Stephan,
I don't think boxing is the cause of the problem here, at least not on the paramter side. If I modify the example to use another type than Double I get the same behavior:
import java.util.function.ToIntFunction;
import java.util.function.ToDoubleFunction;
import java.time.LocalDateTime;
// one class needs to have a main() method
public class HelloWorld
{
// arguments are passed using the text field below this editor
static class Generic<T> {
}
public static <T> String map(Generic<T> o, ToIntFunction<? super T> f) {
return null;
}
public static <T> Number map(Generic<T> o, ToDoubleFunction<? super T> f) {
return null;
}
private static int double2int(LocalDateTime x) {
return 2;
}
public static void main(String[] args) {
Generic<LocalDateTime> oEmpty = new Generic<>();
map(oEmpty, HelloWorld::double2int);
}
}
The problem seems to be with the conversion int -> double. If I modify the example to use a Predicate<T> the return values become incompatible and there is no implicit conversion between bool and int. No everything works as I expect it:
public static <T> String map(Generic<T> o, ToIntFunction<? super T> f) {
return null;
}
public static <T> Number map(Generic<T> o, Predicate<? super T> f) {
return null;
}
private static int double2int(LocalDateTime x) {
return 2;
}
public static void main(String[] args) {
Generic<LocalDateTime> oEmpty = new Generic<>();
map(oEmpty, RadarSimulation::double2int);
}
I could narrow it further down by fixing the generic type T to a custom type A. If I have
public static <T> String g(ToIntFunction<? extends A f) {
return null;
}
public static <T> String g(ToDoubleFunction<? extends A> f) {
return null;
}
private static int double2int(A x) {
return 2;
}
public static void main(String[] args) {
g(HelloWorld::double2int);
}
I get an error, if I remove the wildcard parameter it compiles:
public static <T> String g(ToIntFunction<A> f) {
return null;
}
public static <T> String g(ToDoubleFunction<A> f) {
return null;
}
private static int double2int(Ax) {
return 2;
}
public static void main(String[] args) {
g(RadarSimulation::double2int);
}
I am not sure what to make of this. I am also not sure if this a bug in javac or ejc. I looked the rules of method reference type inference, and from my understanding, the method reference is assignable to both ToIntFunction<T> and To DoubleFunction<T> because the return type int is assignment compatible to double. So the method reference is congruent with both types
Cheers,
Jens
[Updated on: Fri, 25 August 2017 08:52] Report message to a moderator
|
|
|
Re: ECJ error in overload resolution, but not with javac [message #1771486 is a reply to message #1771456] |
Fri, 25 August 2017 14:14 |
Jens Auer Messages: 11 Registered: February 2017 |
Junior Member |
|
|
I've asked on Stackovderflow (https://stackoverflow.com/questions/45878208/overload-resolution-with-method-references-and-function-interface-specialization) to clarify if this is a ECJ or Javac bug. Right now, I think that the code should be rejected with or without wildcards. But this is my simple interpretation of the JLS and it is probably wrong as I am not very familiar with the JLS. In summary, the problem with seems to be the interpretation of the rule to check if one type is more specific than another w.r.t. the actual argument type:
Quote:
15.12.2.5. Choosing the Most Specific Method
If e is an exact method reference expression (§15.13.1), then i) for all i (1 ≤ i ≤ k), Ui is the same as Vi, and ii) one of the following is true:
R2 is void.
R1 <: R2.
R1 is a primitive type, R2 is a reference type, and the compile-time declaration for the method reference has a return type which is a primitive type.
R1 is a reference type, R2 is a primitive type, and the compile-time declaration for the method reference has a return type which is a reference type.
In this case, the types are ToIntFunction and ToDoubleFunction. There is no clause covering the case were both return value types are primitives, so neither of the functional interfaces is more specific than the other. Thus, the code is ambiguous.
But this would leave ecj with the question of why the code is compiled when the wildcards are removed.
|
|
|
Goto Forum:
Current Time: Wed Nov 13 06:35:18 GMT 2024
Powered by FUDForum. Page generated in 0.06339 seconds
|