Overload resolution generally tests that each argument expression is compatible with the corresponding parameter type. In the case in which the argument is a poly method (or constructor) invocation, it is incorrect to test for full compatibility, because this requires forcing all nested implicit lambdas, etc., to be type-checked, per 18.5.2. To preserve the intended invariant that every lambda is type-checked exactly once, the lambdas should not be type-checked until overload resolution is complete.
There are already exceptions to the full compatibility test for arguments during overload resolution:
- Certain lambdas and method references are not considered "pertinent to applicability" (15.12.2.2)
- If the outer invocation requires inference, and one of the parameter types involves a type parameter, the corresponding argument is subject to only part of the compatibility test (18.2.1, 18.5.2).
Unfortunately, neither of these exceptions applies to a nested poly invocation in which the targeted parameter type is a proper type.
Example:
interface Box<T> {
T get();
<R> R map(Function<T,R> f);
}
void print(Object arg) { }
void print(String arg) { }
void test(Box<String> b) {
print(b.map(s -> s.getClass()));
}
Expected behavior: the lambda is ignored during overload resolution of 'map' and 'print'; the 'b.map(...)' argument is tested for compatibility via 18.5.2, but the test stops when bound set B3 is produced. Since B3 is valid for both target types 'Object' and 'String', both 'print' methods are applicable, and 'print(String)' is selected as the most specific. This leads to a type error in the lambda body (found Class, expected String).