RFR: 8177466: Add compiler support for local variable type-inference

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Tue Sep 26 11:59:12 UTC 2017

Just pushed this:


Thanks to everybody for the helpful comments!


On 25/09/17 15:20, Vicente Romero wrote:
> Hi Maurizio,
> Thanks for the updated version. I don't have any major comments. Looks 
> good to me,
> Vicente
> On 09/22/2017 06:52 AM, Maurizio Cimadamore wrote:
>> Here's another revision:
>> http://cr.openjdk.java.net/~mcimadamore/8177466_v3/
>> diagnostics:
>> http://cr.openjdk.java.net/~mcimadamore/8177466_v3/diags.html
>> Changes:
>> * Rewrote logic of type projection in Types.java to use an enum
>> * Added several javadoc on Types.java
>> * added call to baseType() in Attr::attribLazyConstantValue
>> * fixed an issue in TypeHarness where type var was created with null 
>> lower bound (as of this patch, javac is stricter and will assert on 
>> null bounds, as they are problematic to deal with when doing 
>> projections)
>> If there are no major comments, my plan is to push this on 
>> jdk10/master early next week.
>> Thanks!
>> Maurizio
>> On 19/09/17 16:04, Maurizio Cimadamore wrote:
>>> Hi,
>>> I have put together a slightly updated webrev:
>>> * as pointed out, one diagnostic used to say '9' instead of '10' 
>>> (this will likely need to change again because of new release 
>>> cadence, but good enough for now)
>>> * the previous webrev contained a spurious added file (TypeHarness) 
>>> which was caused by a glitch in the lvti branch in the amber repo.
>>> New webrev:
>>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/
>>> New diags:
>>> http://cr.openjdk.java.net/~mcimadamore/8177466_v2/diags.html
>>> Maurizio
>>> On 18/09/17 17:14, Maurizio Cimadamore wrote:
>>>> Hi,
>>>> this change adds support for local variable type inference (JEP 286 
>>>> [1]). A webrev of the change is available here:
>>>> http://cr.openjdk.java.net/~mcimadamore/8177466
>>>> The patch is relatively straightforward: implicitly typed locals 
>>>> are modeled in a similar fashion to implicit lambda parameters: 
>>>> their AST node is a JCVariableDecl whose 'vartype' field is not set 
>>>> (e.g. null).
>>>> There are few tricky parts to this changeset:
>>>> 1) tweak the parser to give 'var' special meaning depending on the 
>>>> version number and context
>>>> 2) Add logic in name resolution to catch bad reference to types 
>>>> named 'var'
>>>> 3) add logic to map initializer type back to a suitable variable 
>>>> declared type
>>>> As for (1), the parser has been extended so as to special case 
>>>> local variables with special name 'var', so that the type will be 
>>>> left out of the corresponding AST representing the variable 
>>>> declaration. This behavior will only affect latest source version.
>>>> The parser has a number of extra checks to prevent 'var to be used 
>>>> in places where it does not belong (according to the spec draft 
>>>> [2]); for instance, declaring a class whose name is 'var' is 
>>>> rejected in the parser. As a general rule, I tried to implement all 
>>>> such checks in the parser, as that gives very early and precise 
>>>> feedback about what's wrong with the code. The changes are 
>>>> implemented in Parser.java.
>>>> There are however errors which cannot be caught in the parser, and 
>>>> that's why (2) is needed. Basically, whenever 'var' is used in a 
>>>> position where it could be either a type or a package name, the 
>>>> parser can't simply rule that out, so we have to accept the code, 
>>>> and give an error if, later on, we discover that 'var' was really 
>>>> used in a type position (see changes in Resolve.java).
>>>> As far as (3) is concerned, we need to 'uncapture' captured types 
>>>> from initializers. That means that if we have a 'var' like this:
>>>> class Foo {
>>>>     void test() {
>>>>         var x = getClass().getSuperClass();
>>>>     }
>>>> }
>>>> The initializer type will be something like Class<? super #CAP>, 
>>>> where #CAP <: Foo
>>>> In this case, the compiler will project this type back to the less 
>>>> specific type Class<?>, and use that as the declared type for 'x'. 
>>>> This logic is defined in Types.java. As this logic is the same 
>>>> logic needed by jshell to render type of standalone expressions, 
>>>> jshell class VarTypePrinter has been removed and jshell has been 
>>>> rewired to point at the (now) official routine in Types. Jshell 
>>>> also needed several other tweaks to (i) accept 'var' and (ii) to 
>>>> deal with non-denotable types (intersection types and anonymous 
>>>> class types) that can be produced by the LVTI machinery (many 
>>>> thanks to Jan for doing those changes!)
>>>> As far as testing is concerned, I wrote several tests to check that 
>>>> the parser was behaving as expected; to check the behavior of the 
>>>> LVTI inference machinery, I wrote a test harness which leverages 
>>>> annotation on 'var' so that we can write down assertions such as:
>>>> @InferredType("java.util.List<? extends java.lang.String>")
>>>> var s = extString();
>>>> Regarding compiler diagnostics, for those interested, a 
>>>> comprehensive list of examples of new diagnostics triggered by the 
>>>> LVTI compiler can be found here:
>>>> http://cr.openjdk.java.net/~mcimadamore/8177466/lvti-diags.html
>>>> Finally, a finder has been added to detect local variable decls 
>>>> whose declared type can be replaced by 'var' - to enable it, the 
>>>> hidden option -XDfind=local should be used.
>>>> Thanks
>>>> Maurizio
>>>> [1] - http://openjdk.java.net/jeps/286
>>>> [2] - http://cr.openjdk.java.net/~dlsmith/local-var-inference.html

More information about the compiler-dev mailing list