RFR: JDK-8191842: JShell: Inferred type information is lost when assigning types to a "var"
Jan Lahoda
jan.lahoda at oracle.com
Mon Jan 15 20:24:59 UTC 2018
Thanks for the comments. An updated patch is here:
http://cr.openjdk.java.net/~jlahoda/8191842/webrev.03/
> Eval:
>
> Nicely documented!
>
> 1218: anonCount is not incremented, so you always have the same
> anonymous class name.
> Which, of course, is a problem if you have more than one:
>
> jshell> class A {}
> | created class A
>
> jshell> new A() { int foo() {return 66; }}
> $2 ==> $0 at 7dc7cbad
>
> jshell> new A() { int hhoo() {return 99; }}
> $3 ==> $0 at 548a9f61
>
> jshell> $3.hhoo()
> An exception has occurred in the compiler (10-internal).
> Please file a bug against the Java compiler via ...
> java.lang.ClassCastException:
> jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol cannot be cast to
> jdk.compiler/com.sun.tools.javac.code.Symbol$MethodSymbol
> at
> jdk.compiler/com.sun.tools.javac.comp.TransTypes.visitApply(TransTypes.java:676)
> at
> jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1634)
> ...
>
> Please include tests with multiple anon classes with member
> accesses.
Oops. Fixed and done.
>
> 402: Nit: "create and explicit class that extens" --> "create AN
> explicit class that EXTENDS"
Fixed.
>
> ExpressionToTypeInfo:
>
> 93: it is conventional, consistent with surrounding vars, and clearer
> to preface predicate names with "is" -- isPrimativeType
Fixed.
>
> 414: for variable declarations with an explicit type, it doesn't seem
> we should be processing anonymous classes in that case
Fixed.
>
> TaskFactory:
>
> The new code is, for every pass through Enter (of which there are
> several per new snippet), iterating through all the
> snippets, filtering for valid vars, looking up the wrap class
> containing the var, iterating through the members of
> that class to find the field representing the var, compiling a cast
> to use to set the type by force. The field type
> is restored before generation.
>
> One concern is that the performance decreases with the number of
> snippets.
> We need to stay aware of long-running JShell instances -- as for a
> user that leaves the jshell tool open for exploration.
> The filtering on fullTypeName being non-null for enhanced types
> limits the heavy processing to these rarer cases,
> so I'm not concerned
>
> I assume all types downstream of these variables are processed after
> Enter finishes?
Yes. I've changed the code to run through the snippets only once.
>
> Thanks for the high-level description of setVariableType, however how
> it is implemented is complex enough to deserve
> documentation (something like the first paragraph).
Fixed.
>
> TreeDissector:
>
> OK
>
> TypePrinter:
>
> OK
>
> Util:
>
> OK
>
> VarSnippet:
>
> OK
>
> Wrap:
>
> Nicely documented!
>
> Tests:
>
> Please include a test covering the bug (above).
Done.
>
> Please include tests covering:
> captured variables
There already were multiple such tests? Or what exactly test is missing?
> extending a variety of complex library classes and interfaces
Done.
> varied argument types
Done.
> parameterized types
Done.
> VarSnippet.typeName() under various conditions
Done.
Jan
>
> -Robert
On 11.1.2018 18:17, Jan Lahoda wrote:
> Hi,
>
> Thanks for all the comments so far. I tried to adjust the code and add
> comments. The updated patch is here:
> http://cr.openjdk.java.net/~jlahoda/8191842/webrev.02/
>
> On 9.1.2018 04:19, Robert Field wrote:
>> Review (partial) --
>>
>>
>> Wrap:
>>
>> 71: The new parameter makes slightly worse a horribly out-of-date method
>> comment (my bad), which could be
>> deleted, but better actually documented -- there are a lot of
>> parameters and they would benefit from an
>> explanation certainly including the new one "enhanced".
>>
>> 82: Built as a list is a good choice.
>>
>> 91: Nit: The comment is helpful but much longer than anything around it
>> and would be more readable formatted.
>> Also, the example type "int" copied from the comment below
>> doesn't make any sense in this context, and so
>> is confusing, maybe they should both be "Foo".
>>
>> Eval:
>>
>> 106: Action at a distance. Document, or better, use another mechanism.
>>
>> 213: The parameter order and cast are inconsistent with all the other
>> process* calls in this switch.
>>
>> 341-343/347: Inconsistent
>>
>> 380-529: Indenting and spacing off
>>
>> 389-393...: I don't get why TreeScanner is run in ExpressionToTypeInfo
>> and then again in Eval with deep interlinking
>> assumptions (like the order of the list). The only data
>> added in the Eval scan is the 'NewClassTree node' which
>> could be in AnonymousDescription. Then you could just
>> iterate the AnonymousDescriptions.
>
> That's not quite simple, as the positions don't match (which could of
> course be solved) and the NewClassTree from the ExpressionToTypeInfo
> also already has the synthetic constructor added. I tried to define one
> method that lists the relevant NewClassTrees in order, and use it on
> both places, which should hopefully make it more robust.
>
> Jan
>
>>
>> 410: I'd make this something less likely to be a captured variable
>> name. That is a unique prefix.
>>
>> 418: ditto
>>
>> 399-445: Anonymous classes are infrequent enough to make this unlikely
>> an issue, so can ignore this comment.
>> The components of a wrap have overhead:
>> they are stored independently for the duration and they
>> are sequentially searched. Within this
>> section these are all strings, so you could use
>> StringBuilder, but the complexity of the extra variables would
>> make that messy. You could just use string '+' rather
>> then 2-5 'add' calls inline -- there is no value in
>> separating adjacent strings (only for Wraps). And the
>> result would probably be more readable.
>>
>> 436: BUG, you are double incrementing 'i'. Please include a test like:
>>
>> class D { D(int foo, String bar) { this.foo = foo; this.bar = bar;
>> } int foo; String bar; }
>> new D(34, "hi") { String z = foo + bar; }
>> $3.z
>>
>> -Robert
>>
>>
>> On 01/05/18 07:07, Jan Lahoda wrote:
>>> Hi,
>>>
>>> Thanks for the comments. An updated patch is here:
>>> http://cr.openjdk.java.net/~jlahoda/8191842/webrev.01/
>>>
>>> I addition to addressing the comments, it also fixes var behavior when
>>> the inferred type is inaccessible - that is allowed during normal
>>> compilation.
>>>
>>> Feedback is welcome,
>>> Jan
>>>
>>> On 13.12.2017 23:31, Robert Field wrote:
>>>> Part 2: tests
>>>>
>>>> ToolSimpleTest is missing the bug number.
>>>>
>>>> VariablesTest needs a copyright update.
>>>>
>>>> Please add tests for:
>>>> * anon classes with added method access
>>>> * anon class scratch var
>>>>
>>>> -Robert
>>>>
>>>>
>>>> On 12/13/17 13:47, Robert Field wrote:
>>>>> Nice generalization.
>>>>>
>>>>> Wrap:
>>>>>
>>>>> 90: this breaks array initialization -- this would no longer work:
>>>>> int[] d = {1, 2, 3}
>>>>>
>>>>> Eval:
>>>>>
>>>>> 559: This code should be designed to work the same for automatically
>>>>> created scratch variables -- aka $1, $2, ... -- they should also have
>>>>> anonymous types.
>>>>>
>>>>> ? 322: Can ei.anonymousClasses be used rather than depending on the
>>>>> naming added in Util.JSHELL_ANONYMOUS?
>>>>>
>>>>> 389, 419, 421, 486-493: the name "constructor" is confusing because it
>>>>> contains other things and not the complete constructor. One of the
>>>>> unwritten rules of wraps in that
>>>>> they consist of a complete component, this code has several hanging
>>>>> pieces. Note the two closing braces in 492, braces et. al. should
>>>>> always be matched in a wrap.
>>>>> The mixture of strings and wraps does make this challenging.
>>>>> I'd suggest doing the bodyParts/extraInit computation first, then
>>>>> build up each component as complete entities: constructor body, class
>>>>> body, class -- all wraps.
>>>>>
>>>>> ExpressionToTypeInfo:
>>>>>
>>>>> 355: Seems fragile to assume that the constructor is first
>>>>>
>>>>> -Robert
>>>>>
>>>>>
>>>>> On 12/13/17 02:02, Jan Lahoda wrote:
>>>>>> Hi,
>>>>>>
>>>>>> When doing:
>>>>>> var r = new Object() { String s; }
>>>>>>
>>>>>> the type of "r" is the anonymous class itself. JShell handles this by
>>>>>> "upgrading" the anonymous class to be a member class, so that it can
>>>>>> be properly used from other snippets.
>>>>>>
>>>>>> But JShell is not prepared for anonymous classes inside the
>>>>>> expression (that are part of the resulting type), like:
>>>>>> ---
>>>>>> jshell> var list = Stream.of(1, 2, 3).map(j -> new Object() { int i =
>>>>>> j; }).collect(Collectors.toList());
>>>>>>
>>>>>> jshell> list.forEach(a -> System.out.println(a.i));
>>>>>> ---
>>>>>>
>>>>>> So, part of the proposed fix is to upgrade all anonymous classes to
>>>>>> member classes if needed. Also, intersection types are cleared from
>>>>>> fields before writing (the intersection types are installed to ensure
>>>>>> var semantics for cases like:
>>>>>> <Z extends Runnable & CharSequence> Z get1() { return null; }
>>>>>> var i1 = get1();
>>>>>> )
>>>>>>
>>>>>> Bug: https://bugs.openjdk.java.net/browse/JDK-8191842
>>>>>> Webrev: http://cr.openjdk.java.net/~jlahoda/8191842/webrev.00/
>>>>>>
>>>>>> Thanks,
>>>>>> Jan
>>>>>>
>>>>>
>>>>
>>
More information about the kulla-dev
mailing list