Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bf5a31a

Browse files
JukkaLmsullivan
authored andcommitted
Refactor rtypes (mypyc/mypyc#82)
Refactor various aspects of rtypes, including these: * Create `RPrimitive` for primitive types and use it instead of separate classes for individual primitive types. Create predefined type objects such as `int_rinstance` which can be shared. * Rename other rtypes: `UserRType` -> `RInstance`, `TupleRType` -> `RTuple`, and `OptionalRType` -> `ROptional`. * Turn some `RType` properties into methods so that it's clear that some of them could perform nontrivial computation or fail. * Turn some `RType` properties into attributes so that it's easier to vary them per-instance. * Remove one level of inheritance. * Rename `supports_unbox` into `is_unboxed`. * Refactor various rtype name tests as they were error-prone and inconsistent. * Use fully-qualified names such as `builtins.int`. * Name of variable-length tuples is `builtins.tuple` instead of `sequence_tuple` (for consistency). Fixes mypyc/mypyc#79.
1 parent d95d74b commit bf5a31a

14 files changed

Lines changed: 378 additions & 472 deletions

doc/dev-intro.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,9 @@ Here are some hints about how to add support for a new primitive type
176176
* Decide whether the primitive type has an "unboxed" representation
177177
(a representation that is not just `PyObject *`).
178178

179-
* Create a subclass of `RType` to support the primitive type. Make sure
180-
`supports_unbox`, `ctype` and various other properties work
181-
correctly for the new type.
179+
* Create a new instance of `RPrimitive` to support the primitive type.
180+
Make sure all the attributes are set correctly and also define
181+
`<foo>_rprimitive` and `is_<foo>_rprimitive`.
182182

183183
* Update `mypyc.genops.Mapper.type_to_rtype()`.
184184

mypyc/emit.py

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55

66
from mypyc.common import REG_PREFIX
77
from mypyc.ops import (
8-
Environment, Label, Register, RType, ObjectRType, TupleRType, UserRType, OptionalRType,
9-
IntRType, type_struct_name
8+
Environment, Label, Register, RType, RTuple, RInstance, ROptional,
9+
RPrimitive, type_struct_name, is_int_rprimitive, is_bool_rprimitive, short_name,
10+
is_list_rprimitive, is_dict_rprimitive, is_tuple_rprimitive, is_none_rprimitive,
11+
object_rprimitive
1012
)
1113

1214

@@ -82,15 +84,15 @@ def temp_name(self) -> str:
8284

8385
# Higher-level operations
8486

85-
def declare_tuple_struct(self, tuple_type: TupleRType) -> None:
86-
if tuple_type.struct_name not in self.context.declarations:
87+
def declare_tuple_struct(self, tuple_type: RTuple) -> None:
88+
if tuple_type.struct_name() not in self.context.declarations:
8789
dependencies = set()
8890
for typ in tuple_type.types:
8991
# XXX other types might eventually need similar behavior
90-
if isinstance(typ, TupleRType):
91-
dependencies.add(typ.struct_name)
92+
if isinstance(typ, RTuple):
93+
dependencies.add(typ.struct_name())
9294

93-
self.context.declarations[tuple_type.struct_name] = HeaderDeclaration(
95+
self.context.declarations[tuple_type.struct_name()] = HeaderDeclaration(
9496
dependencies,
9597
tuple_type.get_c_declaration(),
9698
)
@@ -101,12 +103,12 @@ def emit_inc_ref(self, dest: str, rtype: RType) -> None:
101103
For composite unboxed structures (e.g. tuples) recursively
102104
increment reference counts for each component.
103105
"""
104-
if rtype.name == 'int':
106+
if is_int_rprimitive(rtype):
105107
self.emit_line('CPyTagged_IncRef(%s);' % dest)
106-
elif isinstance(rtype, TupleRType):
108+
elif isinstance(rtype, RTuple):
107109
for i, item_type in enumerate(rtype.types):
108110
self.emit_inc_ref('{}.f{}'.format(dest, i), item_type)
109-
elif not rtype.supports_unbox:
111+
elif not rtype.is_unboxed:
110112
self.emit_line('Py_INCREF(%s);' % dest)
111113
# Otherwise assume it's an unboxed, pointerless value and do nothing.
112114

@@ -116,22 +118,20 @@ def emit_dec_ref(self, dest: str, rtype: RType) -> None:
116118
For composite unboxed structures (e.g. tuples) recursively
117119
decrement reference counts for each component.
118120
"""
119-
if rtype.name == 'int':
121+
if is_int_rprimitive(rtype):
120122
self.emit_line('CPyTagged_DecRef(%s);' % dest)
121-
elif isinstance(rtype, TupleRType):
123+
elif isinstance(rtype, RTuple):
122124
for i, item_type in enumerate(rtype.types):
123125
self.emit_dec_ref('{}.f{}'.format(dest, i), item_type)
124-
elif not rtype.supports_unbox:
126+
elif not rtype.is_unboxed:
125127
self.emit_line('Py_DECREF(%s);' % dest)
126128
# Otherwise assume it's an unboxed, pointerless value and do nothing.
127129

128130
def pretty_name(self, typ: RType) -> str:
129131
pretty_name = typ.name
130-
if pretty_name == 'sequence_tuple':
131-
pretty_name = 'tuple'
132-
elif isinstance(typ, OptionalRType):
132+
if isinstance(typ, ROptional):
133133
pretty_name = '%s or None' % self.pretty_name(typ.value_type)
134-
return pretty_name
134+
return short_name(pretty_name)
135135

136136
def emit_cast(self, src: str, dest: str, typ: RType, declare_dest: bool = False,
137137
custom_message: Optional[str] = None) -> None:
@@ -153,12 +153,12 @@ def emit_cast(self, src: str, dest: str, typ: RType, declare_dest: bool = False,
153153
err = 'PyErr_SetString(PyExc_TypeError, "{} object expected");'.format(
154154
self.pretty_name(typ))
155155
# TODO: Verify refcount handling.
156-
if typ.name in ('list', 'dict'):
156+
if is_list_rprimitive(typ) or is_dict_rprimitive(typ):
157157
if declare_dest:
158158
self.emit_line('PyObject *{};'.format(dest))
159-
if typ.name == 'list':
159+
if is_list_rprimitive(typ):
160160
prefix = 'PyList'
161-
elif typ.name == 'dict':
161+
elif is_dict_rprimitive(typ):
162162
prefix = 'PyDict'
163163
else:
164164
assert False, prefix
@@ -169,7 +169,7 @@ def emit_cast(self, src: str, dest: str, typ: RType, declare_dest: bool = False,
169169
err,
170170
'{} = NULL;'.format(dest),
171171
'}')
172-
elif typ.name == 'sequence_tuple':
172+
elif is_tuple_rprimitive(typ):
173173
if declare_dest:
174174
self.emit_line('{} {};'.format(typ.ctype, dest))
175175
self.emit_lines(
@@ -179,7 +179,7 @@ def emit_cast(self, src: str, dest: str, typ: RType, declare_dest: bool = False,
179179
err,
180180
'{} = NULL;'.format(dest),
181181
'}')
182-
elif isinstance(typ, UserRType):
182+
elif isinstance(typ, RInstance):
183183
if declare_dest:
184184
self.emit_line('PyObject *{};'.format(dest))
185185
self.emit_lines(
@@ -189,7 +189,7 @@ def emit_cast(self, src: str, dest: str, typ: RType, declare_dest: bool = False,
189189
err,
190190
'{} = NULL;'.format(dest),
191191
'}')
192-
elif typ.name == 'None':
192+
elif is_none_rprimitive(typ):
193193
if declare_dest:
194194
self.emit_line('PyObject *{};'.format(dest))
195195
self.emit_lines(
@@ -199,7 +199,7 @@ def emit_cast(self, src: str, dest: str, typ: RType, declare_dest: bool = False,
199199
err,
200200
'{} = NULL;'.format(dest),
201201
'}')
202-
elif isinstance(typ, OptionalRType):
202+
elif isinstance(typ, ROptional):
203203
if declare_dest:
204204
self.emit_line('PyObject *{};'.format(dest))
205205
self.emit_lines(
@@ -236,8 +236,8 @@ def emit_unbox(self, src: str, dest: str, typ: RType, custom_failure: Optional[s
236236
custom_failure]
237237
else:
238238
failure = [raise_exc,
239-
'%s = %s;' % (dest, typ.c_error_value)]
240-
if typ.name == 'int':
239+
'%s = %s;' % (dest, typ.c_error_value())]
240+
if is_int_rprimitive(typ):
241241
if declare_dest:
242242
self.emit_line('CPyTagged {};'.format(dest))
243243
self.emit_line('if (PyLong_Check({}))'.format(src))
@@ -248,7 +248,7 @@ def emit_unbox(self, src: str, dest: str, typ: RType, custom_failure: Optional[s
248248
self.emit_line('else {')
249249
self.emit_lines(*failure)
250250
self.emit_line('}')
251-
elif typ.name == 'bool':
251+
elif is_bool_rprimitive(typ):
252252
# Whether we are borrowing or not makes no difference.
253253
if declare_dest:
254254
self.emit_line('char {};'.format(dest))
@@ -257,7 +257,7 @@ def emit_unbox(self, src: str, dest: str, typ: RType, custom_failure: Optional[s
257257
self.emit_line('} else')
258258
conversion = 'PyObject_IsTrue({})'.format(src)
259259
self.emit_line(' {} = {};'.format(dest, conversion))
260-
elif isinstance(typ, TupleRType):
260+
elif isinstance(typ, RTuple):
261261
self.declare_tuple_struct(typ)
262262
if declare_dest:
263263
self.emit_line('{} {};'.format(typ.ctype, dest))
@@ -271,12 +271,12 @@ def emit_unbox(self, src: str, dest: str, typ: RType, custom_failure: Optional[s
271271
self.emit_line('PyObject *{} = PyTuple_GetItem({}, {});'.format(temp, src, i))
272272
temp2 = self.temp_name()
273273
# Unbox or check the item.
274-
if item_type.supports_unbox:
274+
if item_type.is_unboxed:
275275
self.emit_unbox(temp, temp2, item_type, custom_failure, declare_dest=True,
276276
borrow=borrow)
277277
else:
278278
if not borrow:
279-
self.emit_inc_ref(temp, ObjectRType())
279+
self.emit_inc_ref(temp, object_rprimitive)
280280
self.emit_cast(temp, temp2, item_type, declare_dest=True)
281281
self.emit_line('{}.f{} = {};'.format(dest, i, temp2))
282282
self.emit_line('}')
@@ -295,38 +295,38 @@ def emit_box(self, src: str, dest: str, typ: RType, declare_dest: bool = False)
295295
declaration = 'PyObject *'
296296
else:
297297
declaration = ''
298-
if typ.name == 'int':
298+
if is_int_rprimitive(typ):
299299
# Steal the existing reference if it exists.
300300
self.emit_line('{}{} = CPyTagged_StealAsObject({});'.format(declaration, dest, src))
301-
elif typ.name == 'bool':
301+
elif is_bool_rprimitive(typ):
302302
# TODO: The Py_RETURN macros return the correct PyObject * with reference count
303303
# handling. Relevant here?
304304
self.emit_lines('{}{} = PyBool_FromLong({});'.format(declaration, dest, src))
305-
elif isinstance(typ, TupleRType):
305+
elif isinstance(typ, RTuple):
306306
self.declare_tuple_struct(typ)
307307
self.emit_line('{}{} = PyTuple_New({});'.format(declaration, dest, len(typ.types)))
308308
self.emit_line('if ({} == NULL)'.format(dest))
309309
self.emit_line(' CPyError_OutOfMemory();')
310310
# TODO: Fail if dest is None
311311
for i in range(0, len(typ.types)):
312-
if not typ.supports_unbox:
312+
if not typ.is_unboxed:
313313
self.emit_line('PyTuple_SetItem({}, {}, {}.f{}'.format(dest, i, src, i))
314314
else:
315315
inner_name = self.temp_name()
316316
self.emit_box('{}.f{}'.format(src, i), inner_name, typ.types[i],
317317
declare_dest=True)
318318
self.emit_line('PyTuple_SetItem({}, {}, {});'.format(dest, i, inner_name, i))
319319
else:
320-
assert not typ.supports_unbox
320+
assert not typ.is_unboxed
321321
# Type is boxed -- trivially just assign.
322322
self.emit_line('{}{} = {};'.format(declaration, dest, src))
323323

324324
def emit_error_check(self, value: str, rtype: RType, failure: str) -> None:
325325
"""Emit code for checking a native function return value for uncaught exception."""
326-
if not isinstance(rtype, TupleRType):
327-
self.emit_line('if ({} == {}) {{'.format(value, rtype.c_error_value))
326+
if not isinstance(rtype, RTuple):
327+
self.emit_line('if ({} == {}) {{'.format(value, rtype.c_error_value()))
328328
else:
329-
self.emit_line('if ({}.f0 == {}) {{'.format(value, rtype.types[0].c_error_value))
329+
self.emit_line('if ({}.f0 == {}) {{'.format(value, rtype.types[0].c_error_value()))
330330
self.emit_lines(failure, '}')
331331

332332
def emit_gc_visit(self, target: str, rtype: RType) -> None:
@@ -338,11 +338,11 @@ def emit_gc_visit(self, target: str, rtype: RType) -> None:
338338
if not rtype.is_refcounted:
339339
# Not refcounted -> no pointers -> no GC interaction.
340340
return
341-
elif isinstance(rtype, IntRType):
341+
elif isinstance(rtype, RPrimitive) and rtype.name == 'builtins.int':
342342
self.emit_line('if (CPyTagged_CheckLong({})) {{'.format(target))
343343
self.emit_line('Py_VISIT(CPyTagged_LongAsObject({}));'.format(target))
344344
self.emit_line('}')
345-
elif isinstance(rtype, TupleRType):
345+
elif isinstance(rtype, RTuple):
346346
for i, item_type in enumerate(rtype.types):
347347
self.emit_gc_visit('{}.f{}'.format(target, i), item_type)
348348
elif rtype.ctype == 'PyObject *':
@@ -360,16 +360,16 @@ def emit_gc_clear(self, target: str, rtype: RType) -> None:
360360
if not rtype.is_refcounted:
361361
# Not refcounted -> no pointers -> no GC interaction.
362362
return
363-
elif isinstance(rtype, IntRType):
363+
elif isinstance(rtype, RPrimitive) and rtype.name == 'builtins.int':
364364
self.emit_line('if (CPyTagged_CheckLong({})) {{'.format(target))
365365
self.emit_line('CPyTagged __tmp = {};'.format(target))
366-
self.emit_line('{} = {};'.format(target, rtype.c_undefined_value))
366+
self.emit_line('{} = {};'.format(target, rtype.c_undefined_value()))
367367
self.emit_line('Py_XDECREF(CPyTagged_LongAsObject(__tmp));')
368368
self.emit_line('}')
369-
elif isinstance(rtype, TupleRType):
369+
elif isinstance(rtype, RTuple):
370370
for i, item_type in enumerate(rtype.types):
371371
self.emit_gc_clear('{}.f{}'.format(target, i), item_type)
372-
elif rtype.ctype == 'PyObject *' and rtype.c_undefined_value == 'NULL':
372+
elif rtype.ctype == 'PyObject *' and rtype.c_undefined_value() == 'NULL':
373373
# The simplest case.
374374
self.emit_line('Py_CLEAR({});'.format(target))
375375
else:

0 commit comments

Comments
 (0)