Repository navigation
Refactor type aliases - #5221
Conversation
| return Instance(node, [AnyType(TypeOfAny.special_form)] * len(node.defn.type_vars)) | ||
|
|
||
| def add_builtin_aliases(self, tree: MypyFile) -> None: | ||
| # For historical reasons, the aliases like `List = list` are not defined |
There was a problem hiding this comment.
We could just define those in typeshed actually.
There was a problem hiding this comment.
I would keep this out of this PR. Will pytype an other be OK with this? (There are potential problems with circular dependencies). If yes we can easily do this later, fortunately with this refactoring it is just a matter of removing this patching step (before normalize_type_alias was all over the semanal code).
There was a problem hiding this comment.
I believe other type checkers don't use typing.pyi from typeshed; they have their own versions.
But I agree that this PR is doing enough things already. :)
Currently fails terribly, but maybe python/mypy#5221 will fix it.
|
I found a new crash using this PR's code: (It crashes the same way if it can find |
|
@JelleZijlstra Thanks! TBH I am surprised there is only one crash like this, line and column are never set on |
JukkaL
left a comment
There was a problem hiding this comment.
Thanks for refactoring this! This makes the type alias implementation much cleaner, and also saves some memory since a bunch of attributes are no longer needed. Apparently a few minor bugs were fixed in as well, which is nice.
Left a bunch of minor comments (mostly nits).
| graph[id].fix_suppressed_dependencies(graph) | ||
| if 'typing' in scc: | ||
| # For historical reasons we need to manually add typing aliases | ||
| # for built-in generic collections, see docstring for details. |
There was a problem hiding this comment.
Update comment to be more explicit about which docstring this refers to.
| """Type check a type application (expr[type, ...]). | ||
|
|
||
| There are two different options here, depending on whether expr refers | ||
| to a type alias or directly to a generic class. In first case we need |
There was a problem hiding this comment.
Grammar nit: "In the first case ..."
| to a type alias or directly to a generic class. In first case we need | ||
| to use a dedicated function typeanal.expand_type_aliases. This | ||
| is due to the fact that currently type aliases machinery uses | ||
| unbound type variables, while normal generics use bound ones, |
There was a problem hiding this comment.
Grammar nit: use period or semicolon (e.g. "... bound ones; see ...").
| A = reveal_type(List[T]) | ||
| reveal_type(A) | ||
|
|
||
| will reveal the same type `def (...) -> builtins.list[Any]`. |
There was a problem hiding this comment.
This is a bit unclear. What does "same" mean here? If both of the reveal_types reveal the same types, it would be better to rewrite this as "Both reveal_type instances will reveal the same type ...".
Also, it's worth briefly discussing why the type is list[Any] and not list[T] (because of implicit Any for missing type args?).
| """ | ||
| return self.alias_type_in_runtime(alias.type, alias.tvars, alias.no_args, alias) | ||
|
|
||
| def alias_type_in_runtime(self, target: Type, alias_tvars: List[str], |
There was a problem hiding this comment.
The name of this method is a bit unclear. Maybe rename to alias_type_in_runtime_context, for example?
| UA = Union[T, int] | ||
|
|
||
| cs = CA[str] + 1 # E: Unsupported left operand type for + ("Type alias to Callable") | ||
| cs = CA + 1 # E: Unsupported left operand type for + ("Type alias to Callable") |
There was a problem hiding this comment.
Should we still test also CA[str] + 1, or it no longer relevant?
There was a problem hiding this comment.
It is less relevant because it will fail with something different like "Type application doesn't target a class" in all three cases. But I will add one more test for this.
| reveal_type(cs) # E: Revealed type is 'Any' | ||
|
|
||
| ts = TA[str]() # E: "Type alias to Tuple" not callable | ||
| ts = TA() # E: "Type alias to Tuple" not callable |
| reveal_type(ts) # E: Revealed type is 'Any' | ||
|
|
||
| us = UA[str].x # E: "Type alias to Union" has no attribute "x" | ||
| us = UA.x # E: "Type alias to Union" has no attribute "x" |
| reveal_type(another) # E: Revealed type is 'y.G[y.G*[builtins.int]]' | ||
| reveal_type(second) # E: Revealed type is 'y.G[builtins.str*]' | ||
| reveal_type(last) # E: Revealed type is 'y.G[y.G*]' | ||
| reveal_type(last) # E: Revealed type is 'y.G[y.G*[Any]]' |
There was a problem hiding this comment.
Looks like there was a bug that you fixed here?
There was a problem hiding this comment.
Looks like there was a bug that you fixed here?
Yes, but it was unintentional :-)
| [out] | ||
| == | ||
| c.py:2: error: Argument 1 has incompatible type "int"; expected "str" | ||
| c.py:2: error: Argument 1 to "A" has incompatible type "int"; expected "str" |
There was a problem hiding this comment.
Nice, we can generate a better error message here.
|
Running |
|
@JukkaL Thanks for review! I have addressed all comments and fixed some bugs. |
|
|
||
| -- the order of errors is different with cache | ||
| [case testImportOnTopOfAlias2-skip-cache] | ||
| [case testImportOnTopOfAlias2] |
There was a problem hiding this comment.
Good to have more test cases enabled.
JukkaL
left a comment
There was a problem hiding this comment.
Looks good, thanks for all the fixes! Only one remaining comment. Feel free to merge once you've addressed it and once you've tested this with internal Dropbox codebases. This will greatly simplify future work with type aliases.
| if alias_definition: | ||
| return AnyType(TypeOfAny.special_form) | ||
| # This type is invalid in most runtime contexts. | ||
| kind = (' to Callable' if isinstance(item, CallableType) else |
There was a problem hiding this comment.
The error message logic would better live in mypy.messages.
This refactors type aliases by introducing a dedicated symbol node
TypeAlias, and removing all ad-hoc attributes fromSymbolTableNode. This simplifies the overall logic, and also the fine grained dependency tracking (since now aliases have names).Most of the logic is straightforward. Few comments:
.type_overridewas also used for some overload hacks, I replaced those with a proper fix.ImportedNamebug, I can't find a simple repro (typeshed check test was failing), but the fix is straightforward.*anymore, I think this is more consistent.