|
1 |
| -from typing import Dict, Iterable, List, TypeVar, Mapping, cast |
| 1 | +from typing import Dict, Iterable, List, TypeVar, Mapping, cast, Union, Optional |
2 | 2 |
|
3 | 3 | from mypy.types import (
|
4 | 4 | Type, Instance, CallableType, TypeVisitor, UnboundType, AnyType,
|
@@ -45,6 +45,8 @@ def freshen_function_type_vars(callee: F) -> F:
|
45 | 45 | # TODO(PEP612): fix for ParamSpecType
|
46 | 46 | if isinstance(v, TypeVarType):
|
47 | 47 | tv: TypeVarLikeType = TypeVarType.new_unification_variable(v)
|
| 48 | + elif isinstance(v, TypeVarTupleType): |
| 49 | + tv = TypeVarTupleType.new_unification_variable(v) |
48 | 50 | else:
|
49 | 51 | assert isinstance(v, ParamSpecType)
|
50 | 52 | tv = ParamSpecType.new_unification_variable(v)
|
@@ -135,7 +137,36 @@ def visit_type_var_tuple(self, t: TypeVarTupleType) -> Type:
|
135 | 137 | raise NotImplementedError
|
136 | 138 |
|
137 | 139 | def visit_unpack_type(self, t: UnpackType) -> Type:
|
138 |
| - raise NotImplementedError |
| 140 | + # It is impossible to reasonally implement visit_unpack_type, because |
| 141 | + # unpacking inherently expands to something more like a list of types. |
| 142 | + # |
| 143 | + # Relevant sections that can call unpack should call expand_unpack() |
| 144 | + # instead. |
| 145 | + assert False, "Mypy bug: unpacking must happen at a higher level" |
| 146 | + |
| 147 | + def expand_unpack(self, t: UnpackType) -> Optional[Union[List[Type], Instance, AnyType]]: |
| 148 | + """May return either a list of types to unpack to, any, or a single |
| 149 | + variable length tuple. The latter may not be valid in all contexts. |
| 150 | + """ |
| 151 | + proper_typ = get_proper_type(t.type) |
| 152 | + if isinstance(proper_typ, TypeVarTupleType): |
| 153 | + repl = get_proper_type(self.variables.get(proper_typ.id, t)) |
| 154 | + if isinstance(repl, TupleType): |
| 155 | + return repl.items |
| 156 | + elif isinstance(repl, Instance) and repl.type.fullname == "builtins.tuple": |
| 157 | + return repl |
| 158 | + elif isinstance(repl, AnyType): |
| 159 | + # tuple[Any, ...] would be better, but we don't have |
| 160 | + # the type info to construct that type here. |
| 161 | + return repl |
| 162 | + elif isinstance(repl, TypeVarTupleType): |
| 163 | + return [UnpackType(typ=repl)] |
| 164 | + elif isinstance(repl, UninhabitedType): |
| 165 | + return None |
| 166 | + else: |
| 167 | + raise NotImplementedError("Invalid type to expand: {}".format(repl)) |
| 168 | + else: |
| 169 | + raise NotImplementedError |
139 | 170 |
|
140 | 171 | def visit_parameters(self, t: Parameters) -> Type:
|
141 | 172 | return t.copy_modified(arg_types=self.expand_types(t.arg_types))
|
@@ -179,7 +210,27 @@ def visit_overloaded(self, t: Overloaded) -> Type:
|
179 | 210 | return Overloaded(items)
|
180 | 211 |
|
181 | 212 | def visit_tuple_type(self, t: TupleType) -> Type:
|
182 |
| - return t.copy_modified(items=self.expand_types(t.items)) |
| 213 | + items = [] |
| 214 | + for item in t.items: |
| 215 | + proper_item = get_proper_type(item) |
| 216 | + if isinstance(proper_item, UnpackType): |
| 217 | + unpacked_items = self.expand_unpack(proper_item) |
| 218 | + if unpacked_items is None: |
| 219 | + # TODO: better error, something like tuple of unknown? |
| 220 | + return UninhabitedType() |
| 221 | + elif isinstance(unpacked_items, Instance): |
| 222 | + if len(t.items) == 1: |
| 223 | + return unpacked_items |
| 224 | + else: |
| 225 | + assert False, "Invalid unpack of variable length tuple" |
| 226 | + elif isinstance(unpacked_items, AnyType): |
| 227 | + return unpacked_items |
| 228 | + else: |
| 229 | + items.extend(unpacked_items) |
| 230 | + else: |
| 231 | + items.append(proper_item.accept(self)) |
| 232 | + |
| 233 | + return t.copy_modified(items=items) |
183 | 234 |
|
184 | 235 | def visit_typeddict_type(self, t: TypedDictType) -> Type:
|
185 | 236 | return t.copy_modified(item_types=self.expand_types(t.items.values()))
|
|
0 commit comments