-
Bug
-
Resolution: Fixed
-
P2
-
None
-
Verified
The invocation type of a method invocation must be erased if unchecked conversion was necessary in the applicability test (15.12.2.6). But if the parameter types are erased, that can change the target type of the arguments, resulting in, e.g., different types for implicit lambda parameters or incompatibilities for explicit lambdas that were compatible during applicability testing.
The correct behavior should be to erase the return and thrown types, but to i) perform inference, as usual, for the remaining (not pertinent to applicability) arguments for inferred generic invocations, and then resolve the parameter types based on available bounds; and ii) perform substitutions on parameters targeted by explicit generic invocations.
public <T> Predicate<T> m1(Predicate<T> p, List<T> list) { return p; }
public <S,T> Predicate<T> m2(Function<S,T> f, Predicate<T> p, S s, List<T> list) { return p; }
void test(List l) {
// Unchecked warning expected for all of the following
Predicate<String> p1 = m1((String s) -> s.isEmpty(), l); // no error -- lambda is compatible with target
Predicate<String> p2 = m1(s -> s.isEmpty(), l); // s has type Object; type error
Predicate<String> p3 = this.<String>m1(s -> s.isEmpty(), l); // s has type String; no error
Predicate<String> p4 = m2(x -> x.substring(3), s -> s.isEmpty(), "x", l); // x and s have type String; no error
}
}
The correct behavior should be to erase the return and thrown types, but to i) perform inference, as usual, for the remaining (not pertinent to applicability) arguments for inferred generic invocations, and then resolve the parameter types based on available bounds; and ii) perform substitutions on parameters targeted by explicit generic invocations.
public <T> Predicate<T> m1(Predicate<T> p, List<T> list) { return p; }
public <S,T> Predicate<T> m2(Function<S,T> f, Predicate<T> p, S s, List<T> list) { return p; }
void test(List l) {
// Unchecked warning expected for all of the following
Predicate<String> p1 = m1((String s) -> s.isEmpty(), l); // no error -- lambda is compatible with target
Predicate<String> p2 = m1(s -> s.isEmpty(), l); // s has type Object; type error
Predicate<String> p3 = this.<String>m1(s -> s.isEmpty(), l); // s has type String; no error
Predicate<String> p4 = m2(x -> x.substring(3), s -> s.isEmpty(), "x", l); // x and s have type String; no error
}
}