javap and nullable projection types.

John Rose john.r.rose at
Fri May 10 19:57:17 UTC 2019

On May 10, 2019, at 7:13 AM, Maurizio Cimadamore <maurizio.cimadamore at> wrote:
> On 10/05/2019 14:42, Remi Forax wrote:
>> it's time to resurrect the attribute ValueType ?
> An InnerClass-like attribute like that would be a way to get there

ValueTypes was introduced in order to avoid coining
a new descriptor, and failed in various ways to satisfy
our requirements.  Mainly, it doesn't distinguish old
from new contract references on a per-use basis,
since it is a per-classfile table.  But if it's just a quickie
cache of the Original Truth (at compile time) of the
ACC_VALUE bits from the classes (which javac read),
then it might be useful.

But the analogy with InnerClasses is somewhat

In the def-sites of a nest of classes, InnerClasses is the
Source of Truth for class nesting relations, and is surfaced
by Class.getClasses.  So *those* InnerClasses records
are the moral equivalent of the ACC_VALUE bit in the
header of the classfile:  They tell everybody what's
going on.

But, the InnerClasses attribute is *surprisingly useless*
as a *use-site* attribute.  The InnerClasses records which
pertain to types *outside* the nest (used in the nest)
in theory give a consistent picture of what was the Truth
about class nesting at compile time.  And since we never
migrate Foo$Bar to Foo.Bar or vice versa, that Truth won't
shift much; Foo$Bar just needs a little "official encouragement"
to be treated as Foo.Bar always.

But offhand I can't think of a single API or tool that reads
the *use-site* InnerClasses records.  (Nobody likes my
baby.  It happens.  Sniff.)  It could play a part in rendering
the names used by a classfile, but it doesn't, at least
in the tool we are discussing, which is javap.  See the
example below, where the InnerClasses is present but
unused to render types.

So, if you follow the precedent of InnerClasses, you will
*ignore* it as a reference, at use-sites, for information
about def-sites of types.  Disappointing!

I suggest that javap could render old signatures
the old way and new signatures with a non-Java
marker, like this:

  void bar(Point? flat, Point ptr) { … }

  void bar(inline mypkg.Point, mypkg.Point)
    descriptor: (Qmypkg/Point;Lmypkg/Point;)V
    flags: (0x0000)

That's not out of bounds.  Maybe our problem here
is shaping the boundary of javap.  It should not
try to pretend it's a decompiler, and by definition
shouldn't try to guess at def-site information outside
of the classfile it is rendering.  It's just printing one
classfile, at the JVM level.  So adding V? annotations
looks like the wrong move, at this level.

— John

P.S.  Example of use-site InnerClasses non-use in javap.

$ cat
class Foo {  java.util.Map.Entry bar; }
$ javac
$ javap -v Foo.class
Classfile /private/tmp/Foo.class
  Last modified May 10, 2019; size 301 bytes
  MD5 checksum 40ca9e1413c776b743adc1579051d8f8
  Compiled from ""
class Foo
  minor version: 0
  major version: 55
  flags: (0x0020) ACC_SUPER
  this_class: #2                          // Foo
  super_class: #3                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 1, attributes: 2
Constant pool:
   #1 = Methodref          #3.#15         // java/lang/Object."<init>":()V
   #2 = Class              #16            // Foo
   #3 = Class              #17            // java/lang/Object
   #4 = Utf8               bar
   #5 = Class              #19            // java/util/Map$Entry
   #6 = Utf8               Entry
   #7 = Utf8               InnerClasses
   #8 = Utf8               Ljava/util/Map$Entry;
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               SourceFile
  #14 = Utf8     
  #15 = NameAndType        #9:#10         // "<init>":()V
  #16 = Utf8               Foo
  #17 = Utf8               java/lang/Object
  #18 = Class              #20            // java/util/Map
  #19 = Utf8               java/util/Map$Entry
  #20 = Utf8               java/util/Map
  java.util.Map$Entry bar;
    descriptor: Ljava/util/Map$Entry;
    flags: (0x0000)

    descriptor: ()V
    flags: (0x0000)
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
        line 1: 0
SourceFile: ""
  public static #6= #5 of #18;            // Entry=class java/util/Map$Entry of class java/util/Map

More information about the valhalla-dev mailing list