@@ -491,3 +491,98 @@ expects_type_c_default(C[int])
491491expects_type_c_default_of_int(C[str ])
492492expects_type_c_default_of_int_str(C[str , int ])
493493```
494+
495+ ## Upcasting a ` type[] ` type to a ` Callable ` type
496+
497+ ` type[T] ` accepts the same parameters as ` object.__init__ ` if ` T ` does not have an upper bound. If
498+ ` T ` is bound to a nominal-instance type, ` type[T] ` accepts the same parameters as the constructor of
499+ the class that the instance-type refers to.
500+
501+ ``` py
502+ from ty_extensions import CallableTypeOf
503+
504+ class TakesStrInConstructor :
505+ def __init__ (self , x : int , y : str | None = None ): ...
506+
507+ class TakesIntInConstructor :
508+ def __init__ (self , x : int , y : int | None = None ): ...
509+
510+ def f[
511+ T,
512+ T1: object ,
513+ T2: int ,
514+ T3: TakesStrInConstructor | TakesIntInConstructor,
515+ T4: (TakesStrInConstructor, TakesIntInConstructor),
516+ ](
517+ bare_type: type ,
518+ type_object: type[object ],
519+ type_t_unbound: type[T],
520+ type_t_object_bound: type[T1],
521+ type_int: type[int ],
522+ type_t_int_bound: type[T2],
523+ type_t_union_bound: type[T3],
524+ type_t_constrained: type[T4],
525+ ):
526+ # TODO : these are all `Any` because of typeshed's signature for `type.__call__`.
527+ # We could consider overriding that.
528+ reveal_type(bare_type()) # revealed: Any
529+ reveal_type(type_object()) # revealed: Any
530+
531+ # TODO : we could consider emitting errors for these two, but don't currently,
532+ # for the same reason
533+ reveal_type(bare_type(" " )) # revealed: Any
534+ reveal_type(type_object(" " )) # revealed: Any
535+
536+ reveal_type(type_t_unbound()) # revealed: T@f
537+ reveal_type(type_t_unbound(" " )) # revealed: T@f
538+
539+ reveal_type(type_int()) # revealed: int
540+ reveal_type(type_int(" 1" )) # revealed: int
541+ # error: [invalid-argument-type]
542+ reveal_type(type_int([])) # revealed: int
543+
544+ reveal_type(type_t_union_bound(42 )) # revealed: T3@f
545+ # error: [invalid-argument-type]
546+ reveal_type(type_t_union_bound(42 , " " )) # revealed: T3@f
547+ # error: [invalid-argument-type]
548+ reveal_type(type_t_union_bound(42 , 42 )) # revealed: T3@f
549+
550+ reveal_type(type_t_constrained(42 )) # revealed: T4@f
551+ # error: [invalid-argument-type]
552+ reveal_type(type_t_constrained(42 , " " )) # revealed: T4@f
553+ # error: [invalid-argument-type]
554+ reveal_type(type_t_constrained(42 , 42 )) # revealed: T4@f
555+
556+ def g (
557+ object_class_upcast : CallableTypeOf[object ],
558+ bare_type_upcast : CallableTypeOf[bare_type],
559+ type_object_upcast : CallableTypeOf[type_object],
560+ type_t_unbound_upcast : CallableTypeOf[type_t_unbound],
561+ type_t_object_bound_upcast : CallableTypeOf[type_t_object_bound],
562+ type_int_upcast : CallableTypeOf[type_int],
563+ type_t_int_bound_upcast : CallableTypeOf[type_t_int_bound],
564+ type_t_union_bound_upcast : CallableTypeOf[type_t_union_bound],
565+ type_t_constrained_upcast : CallableTypeOf[type_t_constrained],
566+ ):
567+ reveal_type(object_class_upcast) # revealed: () -> object
568+
569+ # TODO : these two could arguably be `() -> object`,
570+ # but have more dynamic signatures due to typeshed's `type.__call__` annotations.
571+ # We could consider overriding those.
572+ reveal_type(bare_type_upcast) # revealed: (...) -> Any
573+ reveal_type(type_object_upcast) # revealed: (...) -> Any
574+
575+ # TODO : if we did decide to override typeshed's `type.__call__` annotations (see above),
576+ # we should also turn these two into `() -> T@f` / `() -> T1@f`
577+ reveal_type(type_t_unbound_upcast) # revealed: (...) -> T@f
578+ reveal_type(type_t_object_bound_upcast) # revealed: (...) -> T1@f
579+
580+ # revealed: Overload[(x: str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc = 0, /) -> int, (x: str | bytes | bytearray, /, base: SupportsIndex) -> int]
581+ reveal_type(type_int_upcast)
582+ # revealed: Overload[(x: str | Buffer | SupportsInt | SupportsIndex | SupportsTrunc = 0, /) -> T2@f, (x: str | bytes | bytearray, /, base: SupportsIndex) -> T2@f]
583+ reveal_type(type_t_int_bound_upcast)
584+ # revealed: ((x: int, y: str | None = None) -> T3@f) | ((x: int, y: int | None = None) -> T3@f)
585+ reveal_type(type_t_union_bound_upcast)
586+ # revealed: ((x: int, y: str | None = None) -> T4@f) | ((x: int, y: int | None = None) -> T4@f)
587+ reveal_type(type_t_constrained_upcast)
588+ ```
0 commit comments