Skip to content

Type variable substitution in type instances #156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gvanrossum opened this issue Sep 13, 2015 · 1 comment · Fixed by #308
Closed

Type variable substitution in type instances #156

gvanrossum opened this issue Sep 13, 2015 · 1 comment · Fixed by #308

Comments

@gvanrossum
Copy link
Member

[In http://bugs.python.org/issue25087 Stefan Krah wrote:]

If a type scheme is instantiated, should the type variables in the
class body be substituted? This is an example (typed by hand on
a locked down Windows machine, may contain errors):

alpha = TypeVar('alpha')
beta = TypeVar('beta')

class ABTuple(Generic[alpha, beta]):
    def __init__(self, a : alpha, b : beta):
        self.value = (a, b)

get_type_hints(ABTuple.__init__)
 ==> {'b': ~beta, 'a': ~alpha}


IntIntTuple = ABTuple[int, int]

IntIntTuple
 ==> __main__.ABTuple[int, int]

get_type_hints(IntIntTuple.__init__)
{'b': ~beta, 'a': ~alpha}
      ^^^^^^      ^^^^^^

Since the type has been specialized, these should ideally be 'int'.

@gvanrossum
Copy link
Member Author

Unfortunately this info is hard to retrieve at run time. The object returned by the expression IntIntTuple.__init__ is a plain function -- it only knows that it was defined in ABTuple. You could write a custom function though that is passed in separately the IntIntTuple class and the string '__init__' -- it can then do the expansion for you after introspection of IntIntTuple. (See also #136 (comment) and further comments).

gvanrossum pushed a commit that referenced this issue Oct 29, 2016
Fixes #301 now ``List[Tuple[T, T]][int] == List[Tuple[int, int]]``
Fixes #298 now ``Table = Tuple[T, List[T]]`` can be used as generic type alias (as in PEP 484 example)
Fixes #299 now ``class MyTup(Tuple[int, ...]): ...`` is allowed
Fixes #156 (well, it does not substitute the annotations, but makes this task simple even in complex cases, see example in tests)

Also this PR fixes some minor things that I have found while working on this:
* ``List[Union]`` (with bare ``Union``, i.e. without arguments), ``List[Optional]``, ``List[Generic[T]]``, and ``List[ClassVar[int]]`` are not valid and are prohibited now.
* ``Generic`` did not evaluate forward references when asked, now it does.
* ``__qualname__`` was not copied on generic class subscription.
* Type was not erased on instantiation of subclasses of concrete containers (``List``, ``Set``, etc).
* There was an obscure bug in Python 2: sometimes ``_abc_registry`` was erased on instantiation.

The main idea of this PR is to fix the issues mentioned at the top by reusing the existing code. Namely, I pulled flattening and removing duplicates code from ``_Union`` and the tree calculation function ``_subs_tree`` from ``GenericMeta``. As well I moved ``Tuple`` and ``Callable`` _after_ ``GenericMeta`` and made them inherit the latter. So that now all types that could be generic store their info in common way using ``__origin__``, ``__parameters__``, ``__args__``.

I tried to polish this, to be sure that nothing was broken in the process of "refactoring" (also to improve speed). There is no recursion, the substitution tree is recalculated only when necessary. Also I added a lot of tests and many comments/docstrings (also for things added in my recent PRs).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant