|
2 | 2 |
|
3 | 3 | from __future__ import annotations
|
4 | 4 |
|
| 5 | +from typing import Callable |
| 6 | + |
5 | 7 | from mypy.fastparse import parse_type_string
|
6 | 8 | from mypy.nodes import (
|
7 | 9 | MISSING_FALLBACK,
|
8 | 10 | BytesExpr,
|
9 | 11 | CallExpr,
|
10 | 12 | ComplexExpr,
|
| 13 | + Context, |
11 | 14 | DictExpr,
|
12 | 15 | EllipsisExpr,
|
13 | 16 | Expression,
|
|
21 | 24 | RefExpr,
|
22 | 25 | StarExpr,
|
23 | 26 | StrExpr,
|
| 27 | + SymbolTableNode, |
24 | 28 | TupleExpr,
|
25 | 29 | UnaryExpr,
|
26 | 30 | get_member_expr_fullname,
|
@@ -63,12 +67,16 @@ def expr_to_unanalyzed_type(
|
63 | 67 | allow_new_syntax: bool = False,
|
64 | 68 | _parent: Expression | None = None,
|
65 | 69 | allow_unpack: bool = False,
|
| 70 | + lookup_qualified: Callable[[str, Context], SymbolTableNode | None] | None = None, |
66 | 71 | ) -> ProperType:
|
67 | 72 | """Translate an expression to the corresponding type.
|
68 | 73 |
|
69 | 74 | The result is not semantically analyzed. It can be UnboundType or TypeList.
|
70 | 75 | Raise TypeTranslationError if the expression cannot represent a type.
|
71 | 76 |
|
| 77 | + If lookup_qualified is not provided, the expression is expected to be semantically |
| 78 | + analyzed. |
| 79 | +
|
72 | 80 | If allow_new_syntax is True, allow all type syntax independent of the target
|
73 | 81 | Python version (used in stubs).
|
74 | 82 |
|
@@ -101,19 +109,26 @@ def expr_to_unanalyzed_type(
|
101 | 109 | else:
|
102 | 110 | args = [expr.index]
|
103 | 111 |
|
104 |
| - if isinstance(expr.base, RefExpr) and expr.base.fullname in ANNOTATED_TYPE_NAMES: |
105 |
| - # TODO: this is not the optimal solution as we are basically getting rid |
106 |
| - # of the Annotation definition and only returning the type information, |
107 |
| - # losing all the annotations. |
| 112 | + if isinstance(expr.base, RefExpr): |
| 113 | + # Check if the type is Annotated[...]. For this we need the fullname, |
| 114 | + # which must be looked up if the expression hasn't been semantically analyzed. |
| 115 | + base_fullname = None |
| 116 | + if lookup_qualified is not None: |
| 117 | + sym = lookup_qualified(base.name, expr) |
| 118 | + if sym and sym.node: |
| 119 | + base_fullname = sym.node.fullname |
| 120 | + else: |
| 121 | + base_fullname = expr.base.fullname |
108 | 122 |
|
109 |
| - return expr_to_unanalyzed_type(args[0], options, allow_new_syntax, expr) |
110 |
| - else: |
111 |
| - base.args = tuple( |
112 |
| - expr_to_unanalyzed_type( |
113 |
| - arg, options, allow_new_syntax, expr, allow_unpack=True |
114 |
| - ) |
115 |
| - for arg in args |
116 |
| - ) |
| 123 | + if base_fullname is not None and base_fullname in ANNOTATED_TYPE_NAMES: |
| 124 | + # TODO: this is not the optimal solution as we are basically getting rid |
| 125 | + # of the Annotation definition and only returning the type information, |
| 126 | + # losing all the annotations. |
| 127 | + return expr_to_unanalyzed_type(args[0], options, allow_new_syntax, expr) |
| 128 | + base.args = tuple( |
| 129 | + expr_to_unanalyzed_type(arg, options, allow_new_syntax, expr, allow_unpack=True) |
| 130 | + for arg in args |
| 131 | + ) |
117 | 132 | if not base.args:
|
118 | 133 | base.empty_tuple_index = True
|
119 | 134 | return base
|
|
0 commit comments