@@ -1569,11 +1569,11 @@ from typing import Protocol, Any
1569
1569
from ty_extensions import is_fully_static, static_assert, is_assignable_to, is_subtype_of, is_equivalent_to
1570
1570
1571
1571
class RecursiveFullyStatic (Protocol ):
1572
- parent: RecursiveFullyStatic | None
1572
+ parent: RecursiveFullyStatic
1573
1573
x: int
1574
1574
1575
1575
class RecursiveNonFullyStatic (Protocol ):
1576
- parent: RecursiveNonFullyStatic | None
1576
+ parent: RecursiveNonFullyStatic
1577
1577
x: Any
1578
1578
1579
1579
static_assert(is_fully_static(RecursiveFullyStatic))
@@ -1582,16 +1582,111 @@ static_assert(not is_fully_static(RecursiveNonFullyStatic))
1582
1582
static_assert(not is_subtype_of(RecursiveFullyStatic, RecursiveNonFullyStatic))
1583
1583
static_assert(not is_subtype_of(RecursiveNonFullyStatic, RecursiveFullyStatic))
1584
1584
1585
- # TODO : currently leads to a stack overflow
1586
- # static_assert(is_assignable_to(RecursiveFullyStatic, RecursiveNonFullyStatic))
1587
- # static_assert(is_assignable_to(RecursiveNonFullyStatic, RecursiveFullyStatic))
1585
+ static_assert(is_assignable_to(RecursiveNonFullyStatic, RecursiveNonFullyStatic))
1586
+ static_assert(is_assignable_to(RecursiveFullyStatic, RecursiveNonFullyStatic))
1587
+ static_assert(is_assignable_to(RecursiveNonFullyStatic, RecursiveFullyStatic))
1588
1588
1589
1589
class AlsoRecursiveFullyStatic (Protocol ):
1590
- parent: AlsoRecursiveFullyStatic | None
1590
+ parent: AlsoRecursiveFullyStatic
1591
1591
x: int
1592
1592
1593
- # TODO : currently leads to a stack overflow
1594
- # static_assert(is_equivalent_to(AlsoRecursiveFullyStatic, RecursiveFullyStatic))
1593
+ static_assert(is_equivalent_to(AlsoRecursiveFullyStatic, RecursiveFullyStatic))
1594
+
1595
+ class RecursiveOptionalParent (Protocol ):
1596
+ parent: RecursiveOptionalParent | None
1597
+
1598
+ static_assert(is_fully_static(RecursiveOptionalParent))
1599
+
1600
+ static_assert(is_assignable_to(RecursiveOptionalParent, RecursiveOptionalParent))
1601
+
1602
+ static_assert(is_assignable_to(RecursiveNonFullyStatic, RecursiveOptionalParent))
1603
+ static_assert(not is_assignable_to(RecursiveOptionalParent, RecursiveNonFullyStatic))
1604
+
1605
+ class Other (Protocol ):
1606
+ z: str
1607
+
1608
+ def _ (rec : RecursiveFullyStatic, other : Other):
1609
+ reveal_type(rec.parent.parent.parent) # revealed: RecursiveFullyStatic
1610
+
1611
+ rec.parent.parent.parent = rec
1612
+ rec = rec.parent.parent.parent
1613
+
1614
+ rec.parent.parent.parent = other # error: [invalid-assignment]
1615
+ other = rec.parent.parent.parent # error: [invalid-assignment]
1616
+
1617
+ class Foo (Protocol ):
1618
+ @ property
1619
+ def x (self ) -> " Foo" : ...
1620
+
1621
+ class Bar (Protocol ):
1622
+ @ property
1623
+ def x (self ) -> " Bar" : ...
1624
+
1625
+ # TODO : this should pass
1626
+ # error: [static-assert-error]
1627
+ static_assert(is_equivalent_to(Foo, Bar))
1628
+ ```
1629
+
1630
+ ### Nested occurrences of self-reference
1631
+
1632
+ Make sure that we handle self-reference correctly, even if the self-reference appears deeply nested
1633
+ within the type of a protocol member:
1634
+
1635
+ ``` toml
1636
+ [environment ]
1637
+ python-version = " 3.12"
1638
+ ```
1639
+
1640
+ ``` py
1641
+ from __future__ import annotations
1642
+
1643
+ from typing import Protocol, Callable
1644
+ from ty_extensions import Intersection, Not, is_fully_static, is_assignable_to, is_equivalent_to, static_assert
1645
+
1646
+ class C : ...
1647
+
1648
+ class GenericC[T](Protocol):
1649
+ pass
1650
+
1651
+ class Recursive (Protocol ):
1652
+ direct: Recursive
1653
+
1654
+ union: None | Recursive
1655
+
1656
+ intersection1: Intersection[C, Recursive]
1657
+ intersection2: Intersection[C, Not[Recursive]]
1658
+
1659
+ t: tuple[int , tuple[str , Recursive]]
1660
+
1661
+ callable1: Callable[[int ], Recursive]
1662
+ callable2: Callable[[Recursive], int ]
1663
+
1664
+ subtype_of: type[Recursive]
1665
+
1666
+ generic: GenericC[Recursive]
1667
+
1668
+ def method (self , x : Recursive) -> Recursive: ...
1669
+
1670
+ nested: Recursive | Callable[[Recursive | Recursive, tuple[Recursive, Recursive]], Recursive | Recursive]
1671
+
1672
+ static_assert(is_fully_static(Recursive))
1673
+ static_assert(is_equivalent_to(Recursive, Recursive))
1674
+ static_assert(is_assignable_to(Recursive, Recursive))
1675
+
1676
+ def _ (r : Recursive):
1677
+ reveal_type(r.direct) # revealed: Recursive
1678
+ reveal_type(r.union) # revealed: None | Recursive
1679
+ reveal_type(r.intersection1) # revealed: C & Recursive
1680
+ reveal_type(r.intersection2) # revealed: C & ~Recursive
1681
+ reveal_type(r.t) # revealed: tuple[int, tuple[str, Recursive]]
1682
+ reveal_type(r.callable1) # revealed: (int, /) -> Recursive
1683
+ reveal_type(r.callable2) # revealed: (Recursive, /) -> int
1684
+ reveal_type(r.subtype_of) # revealed: type[Recursive]
1685
+ reveal_type(r.generic) # revealed: GenericC[Recursive]
1686
+ reveal_type(r.method(r)) # revealed: Recursive
1687
+ reveal_type(r.nested) # revealed: Recursive | ((Recursive, tuple[Recursive, Recursive], /) -> Recursive)
1688
+
1689
+ reveal_type(r.method(r).callable1(1 ).direct.t[1 ][1 ]) # revealed: Recursive
1595
1690
```
1596
1691
1597
1692
### Regression test: narrowing with self-referential protocols
0 commit comments