/> Alpha-renaming a type variable (to a non-shadowed name) should be
binary and source compatible./
The name is only used internally in the generic class in the
GenericClass attribute, and recompiling with different names will
therefore not affect users of the generic class.
Right. (Like method parameter names, the name is not part of the API,
and exist only to improve the readability of the implementation code.)
/> Reordering or removing type variables is not compatible. (These
first two together match the story for method argument lists; you can
rename method arguments, but not reorder or remove them.)/
Other classes will refer to the generic class using ParamTypes in
their CPs. ParamType provides the type parameters in the order that
the generic type specified at compilation time. Reordering and
recompiling will therefore invalidate all ParamTypes referring to the
modified generic type.
Right. Once you've published Foo<any X, any Y>, clients or subclasses
may have Foo<A,B> in their source files and ParamType[Foo, A, B] in
their binaries, which they expect to retain their meaning. Dropping or
reordering parameters would render these client / subclasses broken.
/> Anyfying an existing erased type variable should be binary and
source compatible./
All ParamTypes referring to a ref-generic type variable will be
providing a reference type (erased) as the type parameter (or no
parameters?). As references are a subset of any, anyfying the type
variable does not invalidate existing ParamTypes.
I have one question here: What happens if I refer to Foo<T> (not any
T) using ParamType[Foo, String]? Is it valid because String is a
reference type, or invalid because Foo is not specializable?
There are two migration situations here:
- Migrating a totally erased generic class to any-generic (Foo<T> to
Foo<any T>)
- Migrating a partially anyfied class (Foo<any T, U> to Foo<any T, any U>)
For the former, there will be no ParamType entries, all references to
Foo<T> will be LFoo; / Constant_Class[Foo]. For the latter, there will
be ParamType entries that specify 'erased' in the appropriate position.
In either case, these remain valid parameterizations after the migration.
To your question: I would say this is invalid, because Foo is not
specializable / lacks a GenericClass attribute.
/> Adding a new type variableat the endof the argument list should be
binary compatible (though not source compatible.) Adding a new type
variable other than at the end is not compatible./
The last point already said that we have to support missing type
parameters, and this point is really just and extension of that. If a
type parameter is not provided, the type variable is assumed to be erased.
Right.
Also, this one interacts with the story for inner classes, and
influences the decision about how to represent enclosing class type
parameters in ParamType (do we have a chain of ParamType, as proposed by
the M3 doc, or do we lift all type parameters to the innermost class?)
The chain approach seems to reduce the impact of generifying an
enclosing class (as per the next item.)
/> Generifying an enclosing scope (evolving|Outer.Inner<U>|to
|Outer<T>.Inner<U>|) should be binary compatible./
At first glance, this might look like anyfying an existing erased type
or generifying a non-generic class. However, the complicating factor
is that the added type variable will also be added to the scope of the
enclosed class, and the question becomes whether we can handle this.
An enclosed class must be compiled with its enclosing class, so the
GenericClass attribute will be updated correctly. The type parameters
to Inner and Outer are provided separately, and any missing type
parameter will still be treated as erased.
Right. Also, with the chain-of-enclosing-descriptors approach, it is
fairly easy for a ParamType[parent=Outer<T>, Inner, U] to recover from
new parameters being added to Outer, whereas if we simply lifted the
Outer parameters onto Inner, now we'd have a difficult time to
reconstruct the actual parameterization.
/> Changing type variable bounds is not binary compatible./
Type variables are erased to their bound, i.e. not necessarily
j.l.Object. Any descriptor that contained a type variable will
therefore contain the bound after compilation. Changing the bound
invalidates the descriptors in existing method refs, and is therefore
binary incompatible. Also, this is not a new constraint, as it already
applies to erased generics.
Right.