Whenever a reference to an inner type of the kind A.B is found,
javac needs to normalize the qualifier type A, so that any
reference to potentially parameterized types are made explicit.
This normalization occurs regardless of whether this type is
explicitly provided in the source code, or inferred from the
enclosing context. Some cases were found where no normalization was
applied to the type qualifier -- e.g. if the qualifier is a
type-variable type. The lack of normalization led to spurious
errors, as the type reference was incorrectly classified as a raw
type. This change adds the missing normalization step. While this
change is generally beneficial, as spurious errors that would cause
compilation to fail are no longer generated, there might be cases
where the additional normalization steps might result in a change
in overload resolution.
For example, assume the following snippet in which the result of
the getter.get() method call is passed to an overloaded method with
two candidates: m(T) and M(Object). Without the patch the following
code prints Object, erroneously; with the patch the following code
prints T, correctly. An erroneous classification of the qualified
type means that the type G.Getter was treated as a raw type and the
result of the method call was Object; the correct classification is
to treat it as T <: Number and the return type of the method
call to be Number. That very classification selects a different
overload m before and after the patch:
static class Usage<T extends Number, G extends Getters<T>> {
public void test(G.Getter getter) {
m(getter.get()); // javac selects one of the overloads for m
}
void m(T t) { System.out.println("T"); }
void m(Object s) { System.out.println("Object"); }
}
static abstract class Getters<T> {
abstract class Getter {
abstract T get();
}
}
public static void main(String[] args) {
new Usage<Integer, Getters<Integer>>().test(new Getters<Integer>() {}.new Getter() { Integer get() { return 42; } });
}