RFR: JDK-8210197: candidate selection during overload resolution can lead to unexpected results for diamond expressions

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Nov 7 08:59:06 UTC 2018

Hi Vicente,
I have some reservation about the fix; the idea behind the code in 
Resolve is that there exist some 'ordering' of error messages (by 
usefulness) - typically if you have something that is NOT APPLICABLE and 
ACCESSIBLE you'd want that to be reported instead of some inaccessible 
symbol found somewhere else. This logic makes a lot of sense given that 
javac scans supertypes from the bottom up - meaning that if you reported 
every single access error, you'd get a lot of spurious hits. So this 
patch has the problem of altering that behavior: now accessibility 
errors can 'trump' applicability ones.

Another problem in the fix (maybe latent) is that you only create the 
access error if the bestSoFar is WRONG_MTH - but not if it's WRONG_MTHS, 
meaning that if the arity of the inapplicable symbols > 1 your patch is 
not effective.

That said, instead of going down this route, I think it's worth asking a 
deeper (and JLS-related) question: what should be the modifiers of the 
synthetic constructor symbols that are used to resolve an anonymous 
class expression as per 15.9.3; that section says that the new 
constructors to be checked must be defined in the supertype of C (in 
this case MyClass itself) and that they must retain same modifiers 
(protected in this case):

"If the class instance creation expression uses <>, then:

[...]If C is an anonymous class, let D be the superclass or 
superinterface of C named by the class instance creation expression.

If D is a class, let c1...cn be the constructors of class D. [...]

A list of methods m1...mn is defined for the purpose of overload 
resolution and type argument inference. For all j (1 ≤ j ≤ n), mj is 
defined in terms of cj as follows:


The modifiers of |m_j | are those of |c_j |"

Under those rules, it is not clear to me how could the logic described 
in the spec succeed in finding the right method - they should both 
appear as non accessible (they are defined in D and in a different 
package, but with 'protected' modifier), so this should apply:

"To choose a constructor, we temporarily consider m1...mn to be members 
of D. One of m1...mn is chosen, as determined by the class instance 
creation expression's argument expressions, using the process specified 
in §15.12.2.

If there is no unique most specific method that is both applicable and 
accessible, then a compile-time error occurs."

For what is worth, even the non-diamond path of the spec text seems to 
suffer from this problem: it delegates blindly to 15.12.2 w/o saying 
what should happen if one of the constructors has protected access, but 
for some reason, javac doesn't seem to have a problem with that - to 
show that, simply remove all generic arguments for the instance creation 
expressions in the test case (e.g. create raw instances of MyClass) and 
see that it works w/o issues.

There are a bunch of possible fixes here - if we are checking a diamond 
anon class we could either run 15.12.2 _pretending we are in D_, or we 
could drop any protected modifier. Both changes, I think, seem to imply 
some spec update.


On 07/11/2018 01:45, Vicente Romero wrote:
> Hi,
> Please review patch for [1] at [2]. The issue was can be explained 
> with these two simple classes:
> ------------------------------------------------------------------------------------------------------ 
> package pkg1;
> public class MyClass<T> {
>     protected MyClass() {}                // (i)
>     protected MyClass(String s) {}    // (ii)
> }
> ------------------------------------------------------------------------------------------------------ 
> package pkg2;
> import pkg1.*;
> class Client {
>     <T> void foo(MyClass<T> m) {}
>     void bar() {
>         foo(new MyClass<>(){});
>     }
> }
> ------------------------------------------------------------------------------------------------------ 
> both constructors are protected and given that we are dealing with a 
> diamond expression, speculative attribution is used. During 
> speculative attribution, javac removes the class definition from the 
> equation meaning that:
> new MyClass<>(){} is rewritten as:
> new MyClass<>()
> the first expression has access to the protected constructors, the 
> other one not.  So as both are protected, they are considered not 
> accessible during overload resolution. Still constructor (i) is 
> applicable but constructor (ii) is not applicable. So my proposal is 
> to create an access error at Resolve::selectBest also for this case. 
> Right now an access error is created only if no other method is found. 
> When an access error is returned during overload resolution, the 
> inaccessible symbol is still used and attached to the AST till the 
> check phase can double check and issue an error or not. As during the 
> check phase the diamond expression is attributed without rewriting, 
> the compiler can then find out that constructor (i) is both applicable 
> and accessible.
> Thanks,
> Vicente
> [1] https://bugs.openjdk.java.net/browse/JDK-8210197
> [2] http://cr.openjdk.java.net/~vromero/8210197/webrev.00/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20181107/60d44546/attachment-0001.html>

More information about the compiler-dev mailing list