python: ensure Python 3 can derive method resolution order
Python 3 removes the original Python method resolution algorithm used
for multiple inheritance and replaces it with a new algorithm that
ensures "monotonicity", this means it ensures that the local method
resolution order remains unchanged even when local hierarchies are used
as part of larger class hierarchies. To ensure this property, certain
class hierarchies which do not preserve monotonicity are refused by
python 3.
The order of the superclasses derived from the annotations
in include/isl/aff_type.h does not preserve monotonicity.
Python 3 reports this through the following error:
class pw_aff(union_pw_aff, multi_pw_aff, pw_multi_aff):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases multi_pw_aff, union_pw_multi_aff, pw_multi_aff
The main problem is that there is no linearization of the classes
in the isl_aff hierarchy that extends all the partial orders
of superclasses. Fix this issue by defining a linearization
of the classes and deriving the partial orders from this linearization.
The linearization is considered from most specific to least specific,
meaning that each class should appear after all of its subclasses.
There are three types of subclass relationships in the isl_aff hierarchy.
- an application of one of the three type constructors (multi,
piecewise and union) yields a type that is more general
than the base type. For example, isl_aff is a subclass of isl_multi_aff
and, similarly, isl_pw_aff is a subclass of isl_multi_pw_aff.
- an application of the type constructors preserves the subclass
relationship. For example, since isl_aff is a subclass of isl_multi_aff,
then so is isl_pw_aff a subclass of isl_pw_multi_aff.
- isl_pw_multi_aff is marked as a subclass of isl_multi_pw_aff.
This is not entirely correct because an isl_multi_pw_aff cannot
represent a partially defined 0-tuple, but for tuples with at least
one element, this is the correct order since the elements
of an isl_multi_pw_aff can be defined over different domains,
while the elements of an isl_pw_multi_aff are all defined over
the same domain.
Along the same lines, isl_union_pw_multi_aff could be considered
a subclass of isl_multi_union_pw_aff. Even though this subclass
relationship is not explicitly marked in the current code base,
the linearization should not prevent this relationship from being
added in the future.
A valid linearization is obtained by starting from the most
specific type (isl_aff) and then successively applying one
of the type constructors in a specific order to one of
the types derived so far, preferring base types that appear
earlier in the linearization, and adding the result to the end of the list.
Adding derived types after their base types covers the first class
of subclass relationships.
Applying a given type constructor to the types in their linearized
order covers the second class of relationships. For example,
since isl_aff is a subclass of isl_multi_aff, it appears
before isl_multi_aff and so the piecewise constructor is applied
to isl_aff before it is applied to isl_multi_aff.
The third class of relationships is handled by the choice
of the order in which the type constructors are considered.
That is, whenever the list is extended, it is extended
through the application of the first constructor in the list
that generates a new type.
It should be noted that the union constructor can only be applied
to the result of an application of the piecewise constructors.
It therefore does not make sense to consider the union constructor
before the piecewise constructor. This leaves three possible
orderings of the constructors: (multi, piecewise, union),
(piecewise, multi, union) and (piecewise, union, multi).
The third one ensures that both isl_multi_pw_aff is derived after
isl_pw_multi_aff and isl_multi_union_pw_aff is derived after
isl_union_pw_multi_aff.
The resulting linearization is as follows:
a pa upa ma pma upma mpa mupa
The order of the superclasses of a class is then
the corresponding subsequence of this list.
Note that the order of this superclasses is the opposite
of the order in which the corresponding annotations appear
in the header file. In particular, the least general
extension appears closest to the annotated type.
To implement this new linearization, pw_multi_aff is moved before
multi_pw_aff and union_pw_multi_aff before multi_pw_aff. Both reorderings
make sense by themselves as they move the more concrete class
closer to the annotated type.
Signed-off-by: Tobias Grosser <tobias@grosser.es>
Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>