Fixed-length unboxed tuple (represented as a C struct). These are used to represent mypy TupleType values (fixed-length Python tuples). Since this is unboxed, the identity of a tuple object is not preserved within compiled code. If the identity of a tuple is important, or there is a
| 750 | |
| 751 | @final |
| 752 | class RTuple(RType): |
| 753 | """Fixed-length unboxed tuple (represented as a C struct). |
| 754 | |
| 755 | These are used to represent mypy TupleType values (fixed-length |
| 756 | Python tuples). Since this is unboxed, the identity of a tuple |
| 757 | object is not preserved within compiled code. If the identity of a |
| 758 | tuple is important, or there is a need to have multiple references |
| 759 | to a single tuple object, a variable-length tuple should be used |
| 760 | (tuple_rprimitive or Tuple[T, ...] with explicit '...'), as they |
| 761 | are boxed. |
| 762 | |
| 763 | These aren't immutable. However, user code won't be able to mutate |
| 764 | individual tuple items. |
| 765 | """ |
| 766 | |
| 767 | is_unboxed = True |
| 768 | |
| 769 | def __init__(self, types: list[RType]) -> None: |
| 770 | self.name = "tuple" |
| 771 | self.types = tuple(types) |
| 772 | self.is_refcounted = any(t.is_refcounted for t in self.types) |
| 773 | # Generate a unique id which is used in naming corresponding C identifiers. |
| 774 | # This is necessary since C does not have anonymous structural type equivalence |
| 775 | # in the same way python can just assign a Tuple[int, bool] to a Tuple[int, bool]. |
| 776 | self.unique_id = self.accept(TupleNameVisitor()) |
| 777 | # Nominally the max c length is 31 chars, but I'm not honestly worried about this. |
| 778 | self.struct_name = f"tuple_{self.unique_id}" |
| 779 | self._ctype = f"{self.struct_name}" |
| 780 | self.error_overlap = all(t.error_overlap for t in self.types) and bool(self.types) |
| 781 | |
| 782 | def accept(self, visitor: RTypeVisitor[T]) -> T: |
| 783 | return visitor.visit_rtuple(self) |
| 784 | |
| 785 | @property |
| 786 | def may_be_immortal(self) -> bool: |
| 787 | return False |
| 788 | |
| 789 | def __str__(self) -> str: |
| 790 | return "tuple[%s]" % ", ".join(str(typ) for typ in self.types) |
| 791 | |
| 792 | def __repr__(self) -> str: |
| 793 | return "<RTuple %s>" % ", ".join(repr(typ) for typ in self.types) |
| 794 | |
| 795 | def __eq__(self, other: object) -> TypeGuard[RTuple]: |
| 796 | return isinstance(other, RTuple) and self.types == other.types |
| 797 | |
| 798 | def __hash__(self) -> int: |
| 799 | return hash((self.name, self.types)) |
| 800 | |
| 801 | def serialize(self) -> JsonDict: |
| 802 | types = [x.serialize() for x in self.types] |
| 803 | return {".class": "RTuple", "types": types} |
| 804 | |
| 805 | @classmethod |
| 806 | def deserialize(cls, data: JsonDict, ctx: DeserMaps) -> RTuple: |
| 807 | types = [deserialize_type(t, ctx) for t in data["types"]] |
| 808 | return RTuple(types) |
| 809 |
no outgoing calls
searching dependent graphs…