RFR: 8177466: Add compiler support for local variable type-inference
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Tue Sep 19 20:24:47 UTC 2017
The type of this is not Component<?, ?> but Component<T, D>. So, when
you use an explicit type, you force the type of 'cp1' to be less sharp,
which then works for the followup assignment. But if you use 'var', the
compiler will just infer whatever type the initializer has, which in
this case is Component<T, D>. And the type of c2.getContainer
(Component<#CAP1, #CAP2>) is not compatible with Component<T, D>.
Maurizio
On 19/09/17 17:44, Sergey Bylokhov wrote:
> Hi, Maurizio.
> One more question about generics, in the code below the "case1"
> compiles successfully, but the "case2" produce an error:
>
> public class testVar {
>
> class Component<T extends Object, D extends Object> {
>
> final Container<?, ?> getContainer() {
> return null;
> }
>
> void windowToLocal() {
> // case1
> Component<?, ?> cp1 = this;
> cp1 = cp1.getContainer();
> // case2
> var cp2 = this;
> cp2 = cp2.getContainer();
> }
> }
> class Container<T extends Object, D extends Object>
> extends Component<T, D> {
>
> }
> }
>
> //error
> testVar.java:13: error: incompatible types:
> testVar.Container<CAP#1,CAP#2> cannot be converted to
> testVar.Component<T,D>
> cp2 = cp2.getContainer();
> ^
> where T,D are type-variables:
> T extends Object declared in class testVar.Component
> D extends Object declared in class testVar.Component
> where CAP#1,CAP#2 are fresh type-variables:
> CAP#1 extends Object from capture of ?
> CAP#2 extends Object from capture of ?
> 1 error
>
> On 9/19/17 08: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