misc_ops.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. """Miscellaneous primitive ops."""
  2. from __future__ import annotations
  3. from mypyc.ir.ops import ERR_FALSE, ERR_MAGIC, ERR_NEVER
  4. from mypyc.ir.rtypes import (
  5. bit_rprimitive,
  6. bool_rprimitive,
  7. c_int_rprimitive,
  8. c_pointer_rprimitive,
  9. c_pyssize_t_rprimitive,
  10. dict_rprimitive,
  11. int_rprimitive,
  12. object_pointer_rprimitive,
  13. object_rprimitive,
  14. str_rprimitive,
  15. )
  16. from mypyc.primitives.registry import ERR_NEG_INT, custom_op, function_op, load_address_op
  17. # Get the 'bool' type object.
  18. load_address_op(name="builtins.bool", type=object_rprimitive, src="PyBool_Type")
  19. # Get the 'range' type object.
  20. load_address_op(name="builtins.range", type=object_rprimitive, src="PyRange_Type")
  21. # Get the boxed Python 'None' object
  22. none_object_op = load_address_op(name="Py_None", type=object_rprimitive, src="_Py_NoneStruct")
  23. # Get the boxed object '...'
  24. ellipsis_op = load_address_op(name="...", type=object_rprimitive, src="_Py_EllipsisObject")
  25. # Get the boxed NotImplemented object
  26. not_implemented_op = load_address_op(
  27. name="builtins.NotImplemented", type=object_rprimitive, src="_Py_NotImplementedStruct"
  28. )
  29. # Get the boxed StopAsyncIteration object
  30. stop_async_iteration_op = load_address_op(
  31. name="builtins.StopAsyncIteration", type=object_rprimitive, src="PyExc_StopAsyncIteration"
  32. )
  33. # id(obj)
  34. function_op(
  35. name="builtins.id",
  36. arg_types=[object_rprimitive],
  37. return_type=int_rprimitive,
  38. c_function_name="CPyTagged_Id",
  39. error_kind=ERR_NEVER,
  40. )
  41. # Return the result of obj.__await()__ or obj.__iter__() (if no __await__ exists)
  42. coro_op = custom_op(
  43. arg_types=[object_rprimitive],
  44. return_type=object_rprimitive,
  45. c_function_name="CPy_GetCoro",
  46. error_kind=ERR_MAGIC,
  47. )
  48. # Do obj.send(value), or a next(obj) if second arg is None.
  49. # (This behavior is to match the PEP 380 spec for yield from.)
  50. # Like next_raw_op, don't swallow StopIteration,
  51. # but also don't propagate an error.
  52. # Can return NULL: see next_op.
  53. send_op = custom_op(
  54. arg_types=[object_rprimitive, object_rprimitive],
  55. return_type=object_rprimitive,
  56. c_function_name="CPyIter_Send",
  57. error_kind=ERR_NEVER,
  58. )
  59. # This is sort of unfortunate but oh well: yield_from_except performs most of the
  60. # error handling logic in `yield from` operations. It returns a bool and passes
  61. # a value by address.
  62. # If the bool is true, then a StopIteration was received and we should return.
  63. # If the bool is false, then the value should be yielded.
  64. # The normal case is probably that it signals an exception, which gets
  65. # propagated.
  66. # Op used for "yield from" error handling.
  67. # See comment in CPy_YieldFromErrorHandle for more information.
  68. yield_from_except_op = custom_op(
  69. arg_types=[object_rprimitive, object_pointer_rprimitive],
  70. return_type=bool_rprimitive,
  71. c_function_name="CPy_YieldFromErrorHandle",
  72. error_kind=ERR_MAGIC,
  73. )
  74. # Create method object from a callable object and self.
  75. method_new_op = custom_op(
  76. arg_types=[object_rprimitive, object_rprimitive],
  77. return_type=object_rprimitive,
  78. c_function_name="PyMethod_New",
  79. error_kind=ERR_MAGIC,
  80. )
  81. # Check if the current exception is a StopIteration and return its value if so.
  82. # Treats "no exception" as StopIteration with a None value.
  83. # If it is a different exception, re-reraise it.
  84. check_stop_op = custom_op(
  85. arg_types=[],
  86. return_type=object_rprimitive,
  87. c_function_name="CPy_FetchStopIterationValue",
  88. error_kind=ERR_MAGIC,
  89. )
  90. # Determine the most derived metaclass and check for metaclass conflicts.
  91. # Arguments are (metaclass, bases).
  92. py_calc_meta_op = custom_op(
  93. arg_types=[object_rprimitive, object_rprimitive],
  94. return_type=object_rprimitive,
  95. c_function_name="CPy_CalculateMetaclass",
  96. error_kind=ERR_MAGIC,
  97. is_borrowed=True,
  98. )
  99. # Import a module (plain)
  100. import_op = custom_op(
  101. arg_types=[str_rprimitive],
  102. return_type=object_rprimitive,
  103. c_function_name="PyImport_Import",
  104. error_kind=ERR_MAGIC,
  105. )
  106. # Table-driven import op.
  107. import_many_op = custom_op(
  108. arg_types=[
  109. object_rprimitive,
  110. c_pointer_rprimitive,
  111. object_rprimitive,
  112. object_rprimitive,
  113. object_rprimitive,
  114. c_pointer_rprimitive,
  115. ],
  116. return_type=bit_rprimitive,
  117. c_function_name="CPyImport_ImportMany",
  118. error_kind=ERR_FALSE,
  119. )
  120. # From import helper op
  121. import_from_many_op = custom_op(
  122. arg_types=[object_rprimitive, object_rprimitive, object_rprimitive, object_rprimitive],
  123. return_type=object_rprimitive,
  124. c_function_name="CPyImport_ImportFromMany",
  125. error_kind=ERR_MAGIC,
  126. )
  127. # Get the sys.modules dictionary
  128. get_module_dict_op = custom_op(
  129. arg_types=[],
  130. return_type=dict_rprimitive,
  131. c_function_name="PyImport_GetModuleDict",
  132. error_kind=ERR_NEVER,
  133. is_borrowed=True,
  134. )
  135. # isinstance(obj, cls)
  136. slow_isinstance_op = function_op(
  137. name="builtins.isinstance",
  138. arg_types=[object_rprimitive, object_rprimitive],
  139. return_type=c_int_rprimitive,
  140. c_function_name="PyObject_IsInstance",
  141. error_kind=ERR_NEG_INT,
  142. truncated_type=bool_rprimitive,
  143. )
  144. # Faster isinstance(obj, cls) that only works with native classes and doesn't perform
  145. # type checking of the type argument.
  146. fast_isinstance_op = function_op(
  147. "builtins.isinstance",
  148. arg_types=[object_rprimitive, object_rprimitive],
  149. return_type=bool_rprimitive,
  150. c_function_name="CPy_TypeCheck",
  151. error_kind=ERR_NEVER,
  152. priority=0,
  153. )
  154. # bool(obj) with unboxed result
  155. bool_op = function_op(
  156. name="builtins.bool",
  157. arg_types=[object_rprimitive],
  158. return_type=c_int_rprimitive,
  159. c_function_name="PyObject_IsTrue",
  160. error_kind=ERR_NEG_INT,
  161. truncated_type=bool_rprimitive,
  162. )
  163. # slice(start, stop, step)
  164. new_slice_op = function_op(
  165. name="builtins.slice",
  166. arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
  167. c_function_name="PySlice_New",
  168. return_type=object_rprimitive,
  169. error_kind=ERR_MAGIC,
  170. )
  171. # type(obj)
  172. type_op = function_op(
  173. name="builtins.type",
  174. arg_types=[object_rprimitive],
  175. c_function_name="PyObject_Type",
  176. return_type=object_rprimitive,
  177. error_kind=ERR_NEVER,
  178. )
  179. # Get 'builtins.type' (base class of all classes)
  180. type_object_op = load_address_op(name="builtins.type", type=object_rprimitive, src="PyType_Type")
  181. # Create a heap type based on a template non-heap type.
  182. # See CPyType_FromTemplate for more docs.
  183. pytype_from_template_op = custom_op(
  184. arg_types=[object_rprimitive, object_rprimitive, str_rprimitive],
  185. return_type=object_rprimitive,
  186. c_function_name="CPyType_FromTemplate",
  187. error_kind=ERR_MAGIC,
  188. )
  189. # Create a dataclass from an extension class. See
  190. # CPyDataclass_SleightOfHand for more docs.
  191. dataclass_sleight_of_hand = custom_op(
  192. arg_types=[object_rprimitive, object_rprimitive, dict_rprimitive, dict_rprimitive],
  193. return_type=bit_rprimitive,
  194. c_function_name="CPyDataclass_SleightOfHand",
  195. error_kind=ERR_FALSE,
  196. )
  197. # Raise ValueError if length of first argument is not equal to the second argument.
  198. # The first argument must be a list or a variable-length tuple.
  199. check_unpack_count_op = custom_op(
  200. arg_types=[object_rprimitive, c_pyssize_t_rprimitive],
  201. return_type=c_int_rprimitive,
  202. c_function_name="CPySequence_CheckUnpackCount",
  203. error_kind=ERR_NEG_INT,
  204. )
  205. # register an implementation for a singledispatch function
  206. register_function = custom_op(
  207. arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
  208. return_type=object_rprimitive,
  209. c_function_name="CPySingledispatch_RegisterFunction",
  210. error_kind=ERR_MAGIC,
  211. )