Search code examples
javagenericsjavactype-inference

Make java compiler output type inference information


Is it possible to get javac to output information about the types it's inferring for method invocations?

For example, I want to know what is inferred for the formal type T in the invocation of bar.

private static <T> void bar() { ... }
public void foo() {
  bar();
}

I was exploring javac -Xprint and friends, but can't find anything that exposes this level of detail.


EDIT Example. I didn't want to put this up originally because it'll complicate answers. I'm primarily interested in getting debug info out of javac. Anyway, this was the motivating example:

public class Scratch {
  private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
    throw (T) t; // Warning: Type safety: Unchecked cast from Throwable to T
  }
  public void foo() {
    sneakyThrow(new Exception());
  }
}

This compiles, but any reasonable decision as to the actual type of T should yield Throwable, and require that foo() throws Throwable. Eclipse seems to think it's RuntimeException. I want to know what javac thinks is happening. If it's a bug in javac's processing of type parameters in the throws clause, the answer to this question would allow me to prove it.


Solution

  • It's possible to see with a lot of detail what javac has inferred / resolved etc. To do that you need to use the hidden / unsupported / undocumented option: -XDverboseResolution. If one want to see all the information then the value to pass is 'all' as in: -XDverboseResolution=all. If one only want to see the instantiation of the generic methods then the option is: -XDverboseResolution=deferred-inference. For the code in the original question I get the following output:

    command: javac -XDverboseResolution=deferred-inference Scratch.java

    output:

    Scratch.java:6: Note: Deferred instantiation of method <T>sneakyThrow(Throwable)
        sneakyThrow(new Exception());
                   ^
      instantiated signature: (Throwable)void
      target-type: <none>
      where T is a type-variable:
        T extends Throwable declared in method <T>sneakyThrow(Throwable)
    Note: Scratch.java uses unchecked or unsafe operations.
    Note: Recompile with -Xlint:unchecked for details.
    

    From this output you can infer that T has been instantiated to Throwable.

    I hope this is what you were looking for.