|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | 5 | import os |
| 6 | +import sys |
6 | 7 | from abc import abstractmethod |
7 | 8 | from collections import defaultdict |
8 | 9 | from collections.abc import Callable, Iterator, Sequence |
|
79 | 80 | from mypy.util import is_sunder, is_typeshed_file, short_type |
80 | 81 | from mypy.visitor import ExpressionVisitor, NodeVisitor, StatementVisitor |
81 | 82 |
|
| 83 | +if sys.version_info >= (3, 12): |
| 84 | + from typing import override |
| 85 | +else: |
| 86 | + from typing_extensions import override |
| 87 | + |
82 | 88 | if TYPE_CHECKING: |
83 | 89 | from mypy.patterns import Pattern |
84 | 90 |
|
@@ -1646,9 +1652,7 @@ def read(cls, data: ReadBuffer) -> Var: |
1646 | 1652 | if tag == LITERAL_COMPLEX: |
1647 | 1653 | v.final_value = complex(read_float_bare(data), read_float_bare(data)) |
1648 | 1654 | elif tag != LITERAL_NONE: |
1649 | | - val = read_literal(data, tag) |
1650 | | - assert not isinstance(val, mypy.types.SentinelValue) |
1651 | | - v.final_value = val |
| 1655 | + v.final_value = read_literal(data, tag) |
1652 | 1656 | assert read_tag(data) == END_TAG |
1653 | 1657 | return v |
1654 | 1658 |
|
@@ -3544,6 +3548,30 @@ def accept(self, visitor: ExpressionVisitor[T]) -> T: |
3544 | 3548 | return visitor.visit_newtype_expr(self) |
3545 | 3549 |
|
3546 | 3550 |
|
| 3551 | +class SentinelExpr(Expression): |
| 3552 | + """PEP 661 sentinel()/Sentinel() call expression. |
| 3553 | +
|
| 3554 | + Marks the rvalue of a sentinel declaration (`X = sentinel("X")`) so that its type |
| 3555 | + is the synthetic per-declaration class in `info`, rather than whatever ordinary |
| 3556 | + call-checking against sentinel's/Sentinel's __init__ signature would produce. |
| 3557 | + """ |
| 3558 | + |
| 3559 | + __slots__ = ("info",) |
| 3560 | + |
| 3561 | + __match_args__ = ("info",) |
| 3562 | + |
| 3563 | + # The synthesized class representing this specific sentinel. |
| 3564 | + info: TypeInfo |
| 3565 | + |
| 3566 | + def __init__(self, info: TypeInfo, line: int, column: int) -> None: |
| 3567 | + super().__init__(line=line, column=column) |
| 3568 | + self.info = info |
| 3569 | + |
| 3570 | + @override |
| 3571 | + def accept(self, visitor: ExpressionVisitor[T]) -> T: |
| 3572 | + return visitor.visit_sentinel_expr(self) |
| 3573 | + |
| 3574 | + |
3547 | 3575 | class AwaitExpr(Expression): |
3548 | 3576 | """Await expression (await ...).""" |
3549 | 3577 |
|
@@ -3666,6 +3694,7 @@ class is generic then it will be a type constructor of higher kind. |
3666 | 3694 | "is_named_tuple", |
3667 | 3695 | "typeddict_type", |
3668 | 3696 | "is_newtype", |
| 3697 | + "is_sentinel", |
3669 | 3698 | "is_intersection", |
3670 | 3699 | "metadata", |
3671 | 3700 | "alt_promote", |
@@ -3806,6 +3835,9 @@ class is generic then it will be a type constructor of higher kind. |
3806 | 3835 | # Is this a newtype type? |
3807 | 3836 | is_newtype: bool |
3808 | 3837 |
|
| 3838 | + # Is this a synthetic type generated for a PEP 661 sentinel()/Sentinel() declaration? |
| 3839 | + is_sentinel: bool |
| 3840 | + |
3809 | 3841 | # Is this a synthesized intersection type? |
3810 | 3842 | is_intersection: bool |
3811 | 3843 |
|
@@ -3860,6 +3892,7 @@ class is generic then it will be a type constructor of higher kind. |
3860 | 3892 | "meta_fallback_to_any", |
3861 | 3893 | "is_named_tuple", |
3862 | 3894 | "is_newtype", |
| 3895 | + "is_sentinel", |
3863 | 3896 | "is_protocol", |
3864 | 3897 | "runtime_protocol", |
3865 | 3898 | "is_final", |
@@ -3907,6 +3940,7 @@ def __init__(self, names: SymbolTable, defn: ClassDef, module_name: str) -> None |
3907 | 3940 | self.is_named_tuple = False |
3908 | 3941 | self.typeddict_type = None |
3909 | 3942 | self.is_newtype = False |
| 3943 | + self.is_sentinel = False |
3910 | 3944 | self.is_intersection = False |
3911 | 3945 | self.metadata = {} |
3912 | 3946 | self.self_type = None |
@@ -4350,6 +4384,7 @@ def write(self, data: WriteBuffer) -> None: |
4350 | 4384 | self.meta_fallback_to_any, |
4351 | 4385 | self.is_named_tuple, |
4352 | 4386 | self.is_newtype, |
| 4387 | + self.is_sentinel, |
4353 | 4388 | self.is_protocol, |
4354 | 4389 | self.runtime_protocol, |
4355 | 4390 | self.is_final, |
@@ -4423,12 +4458,13 @@ def read(cls, data: ReadBuffer) -> TypeInfo: |
4423 | 4458 | ti.meta_fallback_to_any, |
4424 | 4459 | ti.is_named_tuple, |
4425 | 4460 | ti.is_newtype, |
| 4461 | + ti.is_sentinel, |
4426 | 4462 | ti.is_protocol, |
4427 | 4463 | ti.runtime_protocol, |
4428 | 4464 | ti.is_final, |
4429 | 4465 | ti.is_disjoint_base, |
4430 | 4466 | ti.is_intersection, |
4431 | | - ) = read_flags(data, num_flags=11) |
| 4467 | + ) = read_flags(data, num_flags=12) |
4432 | 4468 | ti.metadata = read_json(data) |
4433 | 4469 | tag = read_tag(data) |
4434 | 4470 | if tag != LITERAL_NONE: |
|
0 commit comments