RFR: 8177466: Add compiler support for local variable type-inference
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Tue Sep 19 11:32:41 UTC 2017
On 19/09/17 01:03, Sergey Bylokhov wrote:
> On 9/18/17 16:35, Maurizio Cimadamore wrote:
>> So, I'd suggest that we deal with this as a separate
>> diagnostic-related issue in JDK 10 (I could also reproduce it in 8
>> and 9).
>
> Sure, it was just a random example.
>
> Your comment about jdk8/9 just highlighted one more place, in:
> http://cr.openjdk.java.net/~mcimadamore/8177466/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties.sdiff.html
>
>
> "as of release 9, 'var' is a restricted local variable type and cannot
> be used for type declarations"
>
> I guess it is restricted from jdk 10?
Whoops - correct, well spotted
Maurizio
>
>>
>> Maurizio
>>
>> On 18/09/17 23:44, Sergey Bylokhov wrote:
>>> Hi, Maurizio.
>>> I am not sure is it expected or not, but in some cases the new 'var'
>>> produce some non-easy to read error messages:
>>>
>>> var s = true ? new ArrayList<String>() : new ArrayList<Integer>();
>>> s.add(new String());
>>>
>>> testVar.java:9: error: no suitable method found for add(String)
>>> s.add(new String());
>>> ^
>>> method Collection.add(CAP#1) is not applicable
>>> (argument mismatch; String cannot be converted to CAP#1)
>>> method List.add(CAP#1) is not applicable
>>> (argument mismatch; String cannot be converted to CAP#1)
>>> method AbstractCollection.add(CAP#1) is not applicable
>>> (argument mismatch; String cannot be converted to CAP#1)
>>> method AbstractList.add(CAP#1) is not applicable
>>> (argument mismatch; String cannot be converted to CAP#1)
>>> method ArrayList.add(CAP#1) is not applicable
>>> (argument mismatch; String cannot be converted to CAP#1)
>>> where CAP#1 is a fresh type-variable:
>>> CAP#1 extends INT#1 from capture of ? extends INT#1
>>> where INT#1,INT#2 are intersection types:
>>> INT#1 extends Object,Serializable,Comparable<? extends INT#2>
>>> INT#2 extends Object,Serializable,Comparable<?>
>>> Note: Some messages have been simplified; recompile with
>>> -Xdiags:verbose to get full output
>>>
>>>
>>> On 9/18/17 09: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