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

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Sep 21 16:32:47 UTC 2017

On 21/09/17 17:12, B. Blaser wrote:
> Hi Maurizio,
> On 18 September 2017 at 18:14, Maurizio Cimadamore
> <maurizio.cimadamore at oracle.com> 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).
> While syntactic choices have already been carefully studied, I think a
> dedicated symbolism might make sense here.
> * It could help disambiguating the syntax and facilitate the parsing.
> * The other compilation phases would probably be lightened.
> * Compatibility with legacy sources would be more guarantied.
> I could suggest something like "?" (or any other symbolism) instead of
> a keyword like "var", for example:
>    ? list = new ArrayList<String>();
> After having implemented a solution with "var", what would be your
> opinion on using a dedicated symbolism?
Thanks for your email - at this point syntactic decisions are settled. 
There has been a poll an year ago or so:


> Bernard
>> 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