Handle directly applying type arguments to a variadic Callable. This is needed in situations where e.g. variadic class object appears in runtime context. For example: class C(Generic[T, Unpack[Ts]]): ... x = C[int, str]() We simply group the argument
(
self, t: CallableType, args: Sequence[Type], ctx: Context
)
| 5029 | return self.named_type("typing._SpecialForm") |
| 5030 | |
| 5031 | def split_for_callable( |
| 5032 | self, t: CallableType, args: Sequence[Type], ctx: Context |
| 5033 | ) -> list[Type]: |
| 5034 | """Handle directly applying type arguments to a variadic Callable. |
| 5035 | |
| 5036 | This is needed in situations where e.g. variadic class object appears in |
| 5037 | runtime context. For example: |
| 5038 | class C(Generic[T, Unpack[Ts]]): ... |
| 5039 | x = C[int, str]() |
| 5040 | |
| 5041 | We simply group the arguments that need to go into Ts variable into a TupleType, |
| 5042 | similar to how it is done in other places using split_with_prefix_and_suffix(). |
| 5043 | """ |
| 5044 | if t.is_type_obj(): |
| 5045 | # Type arguments must map to class type variables, ignoring constructor vars. |
| 5046 | vars = t.type_object().defn.type_vars |
| 5047 | else: |
| 5048 | vars = list(t.variables) |
| 5049 | args = flatten_nested_tuples(args) |
| 5050 | |
| 5051 | # TODO: this logic is duplicated with semanal_typeargs. |
| 5052 | for tv, arg in zip(t.variables, args): |
| 5053 | if isinstance(tv, ParamSpecType): |
| 5054 | if not isinstance( |
| 5055 | get_proper_type(arg), (Parameters, ParamSpecType, AnyType, UnboundType) |
| 5056 | ): |
| 5057 | self.chk.fail( |
| 5058 | "Can only replace ParamSpec with a parameter types list or" |
| 5059 | f" another ParamSpec, got {format_type(arg, self.chk.options)}", |
| 5060 | ctx, |
| 5061 | ) |
| 5062 | return [AnyType(TypeOfAny.from_error)] * len(vars) |
| 5063 | |
| 5064 | # TODO: in future we may want to support type application to variadic functions. |
| 5065 | if ( |
| 5066 | not vars |
| 5067 | or not any(isinstance(v, TypeVarTupleType) for v in vars) |
| 5068 | or not t.is_type_obj() |
| 5069 | ): |
| 5070 | return list(args) |
| 5071 | info = t.type_object() |
| 5072 | # We reuse the logic from semanal phase to reduce code duplication. |
| 5073 | fake = Instance(info, args, line=ctx.line, column=ctx.column) |
| 5074 | # This code can be only called either from checking a type application, or from |
| 5075 | # checking a type alias (after the caller handles no_args aliases), so we know it |
| 5076 | # was initially an IndexExpr, and we allow empty tuple type arguments. |
| 5077 | if not validate_instance(fake, self.chk.fail, indexed=True): |
| 5078 | fix_instance( |
| 5079 | fake, self.chk.fail, self.chk.note, disallow_any=False, options=self.chk.options |
| 5080 | ) |
| 5081 | args = list(fake.args) |
| 5082 | |
| 5083 | prefix = next(i for (i, v) in enumerate(vars) if isinstance(v, TypeVarTupleType)) |
| 5084 | suffix = len(vars) - prefix - 1 |
| 5085 | tvt = vars[prefix] |
| 5086 | assert isinstance(tvt, TypeVarTupleType) |
| 5087 | start, middle, end = split_with_prefix_and_suffix(tuple(args), prefix, suffix) |
| 5088 | return list(start) + [TupleType(list(middle), tvt.tuple_fallback)] + list(end) |
no test coverage detected