@@ -439,6 +439,157 @@ def _(x: Bar[int]):
439439 reveal_type(x) # revealed: int | list[int]
440440```
441441
442+ ### Recursive aliases in operations
443+
444+ ``` py
445+ from typing import Callable, Iterator, Literal, TypedDict, overload
446+ from ty_extensions import all_members, has_member
447+
448+ class RecursiveItem : ...
449+
450+ type RecursiveUnion = RecursiveItem | RecursiveUnion
451+
452+ def subscript_recursive_alias (x : RecursiveUnion):
453+ # error: [not-subscriptable] "Cannot subscript object of type `RecursiveItem` with no `__getitem__` method"
454+ reveal_type(x[0 ]) # revealed: Unknown
455+
456+ class RecursiveIterableItem :
457+ def __iter__ (self ) -> Iterator[" RecursiveIterable" ]:
458+ return iter ([self ])
459+
460+ type RecursiveIterable = RecursiveIterableItem | RecursiveIterable
461+
462+ def iterate_recursive_alias (x : RecursiveIterable):
463+ for y in x:
464+ reveal_type(y) # revealed: RecursiveIterableItem | Unknown
465+
466+ def star_recursive_alias (x : RecursiveIterable):
467+ def g (* args : object ): ...
468+
469+ g(* x)
470+
471+ class RecursiveCallable :
472+ def __call__ (self ) -> " DunderRecursive" :
473+ return self
474+
475+ type DunderRecursive = RecursiveCallable | DunderRecursive
476+
477+ class HasRecursiveLen :
478+ __len__ : DunderRecursive = RecursiveCallable()
479+
480+ def len_recursive_alias (x : HasRecursiveLen):
481+ # error: [invalid-argument-type] "Argument to function `len` is incorrect: Expected `Sized`, found `HasRecursiveLen`"
482+ reveal_type(len (x)) # revealed: int
483+
484+ class RecursiveMembers :
485+ attr: int
486+
487+ type RecursiveMembersAlias = RecursiveMembers | RecursiveMembersAlias
488+
489+ def list_recursive_alias_members (x : RecursiveMembersAlias):
490+ all_members(x)
491+ reveal_type(has_member(x, " attr" )) # revealed: Literal[False]
492+
493+ class RecursiveAttribute :
494+ attr: int
495+
496+ type RecursiveAttributeAlias = RecursiveAttribute | RecursiveAttributeAlias
497+
498+ def assign_recursive_alias_attribute (x : RecursiveAttributeAlias):
499+ x.attr = 1
500+
501+ def delete_recursive_alias_attribute (x : RecursiveAttributeAlias):
502+ del x.attr
503+
504+ class RecursiveKwargs (TypedDict ):
505+ kind: Literal[" a" ]
506+ a: int
507+
508+ type RecursiveKwargsAlias = RecursiveKwargs | RecursiveKwargsAlias
509+
510+ def call_with_recursive_kwargs_alias (x : RecursiveKwargsAlias):
511+ def g (a : int ): ...
512+
513+ g(** x)
514+
515+ def narrow_recursive_typed_dict_alias (x : RecursiveKwargsAlias):
516+ if x[" kind" ] == " a" :
517+ reveal_type(x) # revealed: RecursiveKwargs
518+
519+ type RecursiveDecoratorReturn = Callable[[int ], int ] | RecursiveDecoratorReturn
520+
521+ def recursive_decorator_return (fn : Callable[[int ], int ]) -> RecursiveDecoratorReturn: ...
522+ @recursive_decorator_return
523+ def decorated (x : int ) -> int :
524+ return x
525+
526+ reveal_type(decorated) # revealed: ((int, /) -> int) | Unknown
527+
528+ class BaseWithMethod :
529+ def method (self ) -> None : ...
530+
531+ class RecursiveSuperOwner (BaseWithMethod ): ...
532+
533+ type RecursiveSuperOwnerAlias = RecursiveSuperOwner | RecursiveSuperOwnerAlias
534+
535+ def recursive_super_owner (x : RecursiveSuperOwnerAlias):
536+ super (RecursiveSuperOwner, x).method()
537+
538+ type RecursiveTuple = tuple[RecursiveTuple]
539+
540+ @overload
541+ def overloaded_recursive_tuple (x : int ) -> int : ...
542+ @overload
543+ def overloaded_recursive_tuple (x : str ) -> str : ...
544+ def overloaded_recursive_tuple (x : object ) -> object :
545+ return x
546+
547+ def expand_recursive_tuple_argument (x : RecursiveTuple):
548+ # error: [no-matching-overload] "No overload of function `overloaded_recursive_tuple` matches arguments"
549+ reveal_type(overloaded_recursive_tuple(x)) # revealed: Unknown
550+
551+ @overload
552+ def overloaded_recursive_tuple_variadic (x : int ) -> int : ...
553+ @overload
554+ def overloaded_recursive_tuple_variadic (x : int , y : int ) -> str : ...
555+ def overloaded_recursive_tuple_variadic (* args : object ) -> object :
556+ return args
557+
558+ def expand_recursive_variadic_tuple_argument (x : RecursiveTuple):
559+ # error: [invalid-argument-type] "Argument to function `overloaded_recursive_tuple_variadic` is incorrect: Expected `int`, found `RecursiveTuple`"
560+ reveal_type(overloaded_recursive_tuple_variadic(* x)) # revealed: Unknown
561+
562+ type RecursiveClassInfo = type[int ] | RecursiveClassInfo
563+
564+ def narrow_recursive_classinfo (x : object , y : RecursiveClassInfo):
565+ if isinstance (x, y):
566+ reveal_type(x) # revealed: object
567+
568+ def narrow_recursive_subclassinfo (x : type[object ], y : RecursiveClassInfo):
569+ if issubclass (x, y):
570+ reveal_type(x) # revealed: type
571+
572+ type RecursiveSingleValuedTuple = tuple[None , RecursiveSingleValuedTuple]
573+
574+ def narrow_recursive_single_valued_tuple (x : object , y : RecursiveSingleValuedTuple):
575+ if x == y:
576+ reveal_type(x) # revealed: object
577+ ```
578+
579+ ### Parser-recovery operation regressions
580+
581+ ``` py
582+ # error: [invalid-syntax] "Expected an expression"
583+ type CrashyOperation = | CrashyOperation
584+
585+ def subscript_recovered_alias (x : CrashyOperation):
586+ reveal_type(x[0 ]) # revealed: Unknown
587+
588+ def iterate_recovered_alias (x : CrashyOperation):
589+ for y in x:
590+ reveal_type(y) # revealed: Unknown
591+ ```
592+
442593### With legacy generic
443594
444595``` py
0 commit comments