Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use emit_lines instead of bunches of emit_line calls #15767

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions mypyc/codegen/emit.py
Original file line number Diff line number Diff line change
Expand Up @@ -759,10 +759,12 @@ def emit_union_cast(
self.emit_line(f"PyObject *{dest};")
good_label = self.new_label()
if optional:
self.emit_line(f"if ({src} == NULL) {{")
self.emit_line(f"{dest} = {self.c_error_value(typ)};")
self.emit_line(f"goto {good_label};")
self.emit_line("}")
self.emit_lines(
f"if ({src} == NULL) {{",
f"{dest} = {self.c_error_value(typ)};",
f"goto {good_label};",
"}",
)
for item in typ.items:
self.emit_cast(
src,
Expand Down Expand Up @@ -1030,9 +1032,11 @@ def emit_box(
self.emit_line(f"{declaration}{dest} = PyFloat_FromDouble({src});")
elif isinstance(typ, RTuple):
self.declare_tuple_struct(typ)
self.emit_line(f"{declaration}{dest} = PyTuple_New({len(typ.types)});")
self.emit_line(f"if (unlikely({dest} == NULL))")
self.emit_line(" CPyError_OutOfMemory();")
self.emit_lines(
f"{declaration}{dest} = PyTuple_New({len(typ.types)});",
f"if (unlikely({dest} == NULL))",
" CPyError_OutOfMemory();",
)
# TODO: Fail if dest is None
for i in range(0, len(typ.types)):
if not typ.is_unboxed:
Expand Down Expand Up @@ -1072,9 +1076,11 @@ def emit_gc_visit(self, target: str, rtype: RType) -> None:
# Not refcounted -> no pointers -> no GC interaction.
return
elif isinstance(rtype, RPrimitive) and rtype.name == "builtins.int":
self.emit_line(f"if (CPyTagged_CheckLong({target})) {{")
self.emit_line(f"Py_VISIT(CPyTagged_LongAsObject({target}));")
self.emit_line("}")
self.emit_lines(
f"if (CPyTagged_CheckLong({target})) {{",
f"Py_VISIT(CPyTagged_LongAsObject({target}));",
"}",
)
elif isinstance(rtype, RTuple):
for i, item_type in enumerate(rtype.types):
self.emit_gc_visit(f"{target}.f{i}", item_type)
Expand All @@ -1094,11 +1100,13 @@ def emit_gc_clear(self, target: str, rtype: RType) -> None:
# Not refcounted -> no pointers -> no GC interaction.
return
elif isinstance(rtype, RPrimitive) and rtype.name == "builtins.int":
self.emit_line(f"if (CPyTagged_CheckLong({target})) {{")
self.emit_line(f"CPyTagged __tmp = {target};")
self.emit_line(f"{target} = {self.c_undefined_value(rtype)};")
self.emit_line("Py_XDECREF(CPyTagged_LongAsObject(__tmp));")
self.emit_line("}")
self.emit_lines(
f"if (CPyTagged_CheckLong({target})) {{",
f"CPyTagged __tmp = {target};",
f"{target} = {self.c_undefined_value(rtype)};",
"Py_XDECREF(CPyTagged_LongAsObject(__tmp));",
"}",
)
elif isinstance(rtype, RTuple):
for i, item_type in enumerate(rtype.types):
self.emit_gc_clear(f"{target}.f{i}", item_type)
Expand Down Expand Up @@ -1156,9 +1164,9 @@ def _emit_traceback(
def emit_unbox_failure_with_overlapping_error_value(
self, dest: str, typ: RType, failure: str
) -> None:
self.emit_line(f"if ({dest} == {self.c_error_value(typ)} && PyErr_Occurred()) {{")
self.emit_line(failure)
self.emit_line("}")
self.emit_lines(
f"if ({dest} == {self.c_error_value(typ)} && PyErr_Occurred()) {{", failure, "}"
)


def c_array_initializer(components: list[str], *, indented: bool = False) -> str:
Expand Down
182 changes: 96 additions & 86 deletions mypyc/codegen/emitclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,9 +472,7 @@ def trait_offset_table_name(trait: ClassIR) -> str:
)

# Emit vtable setup function
emitter.emit_line("static bool")
emitter.emit_line(f"{NATIVE_PREFIX}{vtable_setup_name}(void)")
emitter.emit_line("{")
emitter.emit_lines("static bool", f"{NATIVE_PREFIX}{vtable_setup_name}(void)", "{")

if base.allow_interpreted_subclasses and not shadow:
emitter.emit_line(f"{NATIVE_PREFIX}{vtable_setup_name}_shadow();")
Expand All @@ -489,8 +487,7 @@ def trait_offset_table_name(trait: ClassIR) -> str:

generate_vtable(base.vtable_entries, vtable_name, emitter, subtables, shadow)

emitter.emit_line("return 1;")
emitter.emit_line("}")
emitter.emit_lines("return 1;", "}")

return vtable_name if not subtables else f"{vtable_name} + {len(subtables) * 3}"

Expand Down Expand Up @@ -555,20 +552,24 @@ def generate_setup_for_class(
emitter: Emitter,
) -> None:
"""Generate a native function that allocates an instance of a class."""
emitter.emit_line("static PyObject *")
emitter.emit_line(f"{func_name}(PyTypeObject *type)")
emitter.emit_line("{")
emitter.emit_line(f"{cl.struct_name(emitter.names)} *self;")
emitter.emit_line(f"self = ({cl.struct_name(emitter.names)} *)type->tp_alloc(type, 0);")
emitter.emit_line("if (self == NULL)")
emitter.emit_line(" return NULL;")
emitter.emit_lines(
"static PyObject *",
f"{func_name}(PyTypeObject *type)",
"{",
f"{cl.struct_name(emitter.names)} *self;",
f"self = ({cl.struct_name(emitter.names)} *)type->tp_alloc(type, 0);",
"if (self == NULL)",
" return NULL;",
)

if shadow_vtable_name:
emitter.emit_line(f"if (type != {emitter.type_struct_name(cl)}) {{")
emitter.emit_line(f"self->vtable = {shadow_vtable_name};")
emitter.emit_line("} else {")
emitter.emit_line(f"self->vtable = {vtable_name};")
emitter.emit_line("}")
emitter.emit_lines(
f"if (type != {emitter.type_struct_name(cl)}) {{",
f"self->vtable = {shadow_vtable_name};",
"} else {",
f"self->vtable = {vtable_name};",
"}",
)
else:
emitter.emit_line(f"self->vtable = {vtable_name};")
for i in range(0, len(cl.bitmap_attrs), BITMAP_BITS):
Expand Down Expand Up @@ -599,8 +600,7 @@ def generate_setup_for_class(
"}",
)

emitter.emit_line("return (PyObject *)self;")
emitter.emit_line("}")
emitter.emit_lines("return (PyObject *)self;", "}")


def generate_constructor_for_class(
Expand All @@ -612,37 +612,39 @@ def generate_constructor_for_class(
emitter: Emitter,
) -> None:
"""Generate a native function that allocates and initializes an instance of a class."""
emitter.emit_line(f"{native_function_header(fn, emitter)}")
emitter.emit_line("{")
emitter.emit_line(f"PyObject *self = {setup_name}({emitter.type_struct_name(cl)});")
emitter.emit_line("if (self == NULL)")
emitter.emit_line(" return NULL;")
emitter.emit_lines(
f"{native_function_header(fn, emitter)}",
"{",
f"PyObject *self = {setup_name}({emitter.type_struct_name(cl)});",
"if (self == NULL)",
" return NULL;",
)
args = ", ".join(["self"] + [REG_PREFIX + arg.name for arg in fn.sig.args])
if init_fn is not None:
emitter.emit_line(
emitter.emit_lines(
"char res = {}{}{}({});".format(
emitter.get_group_prefix(init_fn.decl),
NATIVE_PREFIX,
init_fn.cname(emitter.names),
args,
)
),
"if (res == 2) {",
"Py_DECREF(self);",
"return NULL;",
"}",
)
emitter.emit_line("if (res == 2) {")
emitter.emit_line("Py_DECREF(self);")
emitter.emit_line("return NULL;")
emitter.emit_line("}")

# If there is a nontrivial ctor that we didn't define, invoke it via tp_init
elif len(fn.sig.args) > 1:
emitter.emit_line(f"int res = {emitter.type_struct_name(cl)}->tp_init({args});")

emitter.emit_line("if (res < 0) {")
emitter.emit_line("Py_DECREF(self);")
emitter.emit_line("return NULL;")
emitter.emit_line("}")
emitter.emit_lines(
f"int res = {emitter.type_struct_name(cl)}->tp_init({args});",
"if (res < 0) {",
"Py_DECREF(self);",
"return NULL;",
"}",
)

emitter.emit_line("return self;")
emitter.emit_line("}")
emitter.emit_lines("return self;", "}")


def generate_init_for_class(cl: ClassIR, init_fn: FuncIR, emitter: Emitter) -> str:
Expand All @@ -654,9 +656,9 @@ def generate_init_for_class(cl: ClassIR, init_fn: FuncIR, emitter: Emitter) -> s
"""
func_name = f"{cl.name_prefix(emitter.names)}_init"

emitter.emit_line("static int")
emitter.emit_line(f"{func_name}(PyObject *self, PyObject *args, PyObject *kwds)")
emitter.emit_line("{")
emitter.emit_lines(
"static int", f"{func_name}(PyObject *self, PyObject *args, PyObject *kwds)", "{"
)
if cl.allow_interpreted_subclasses or cl.builtin_base:
emitter.emit_line(
"return {}{}(self, args, kwds) != NULL ? 0 : -1;".format(
Expand All @@ -678,17 +680,19 @@ def generate_new_for_class(
init_fn: FuncIR | None,
emitter: Emitter,
) -> None:
emitter.emit_line("static PyObject *")
emitter.emit_line(f"{func_name}(PyTypeObject *type, PyObject *args, PyObject *kwds)")
emitter.emit_line("{")
emitter.emit_lines(
"static PyObject *",
f"{func_name}(PyTypeObject *type, PyObject *args, PyObject *kwds)",
"{",
)
# TODO: Check and unbox arguments
if not cl.allow_interpreted_subclasses:
emitter.emit_line(f"if (type != {emitter.type_struct_name(cl)}) {{")
emitter.emit_line(
'PyErr_SetString(PyExc_TypeError, "interpreted classes cannot inherit from compiled");'
emitter.emit_lines(
f"if (type != {emitter.type_struct_name(cl)}) {{",
'PyErr_SetString(PyExc_TypeError, "interpreted classes cannot inherit from compiled");',
"return NULL;",
"}",
)
emitter.emit_line("return NULL;")
emitter.emit_line("}")

if not init_fn or cl.allow_interpreted_subclasses or cl.builtin_base or cl.is_serializable():
# Match Python semantics -- __new__ doesn't call __init__.
Expand All @@ -697,30 +701,32 @@ def generate_new_for_class(
# __new__ of a native class implicitly calls __init__ so that we
# can enforce that instances are always properly initialized. This
# is needed to support always defined attributes.
emitter.emit_line(f"PyObject *self = {setup_name}(type);")
emitter.emit_lines("if (self == NULL)", " return NULL;")
emitter.emit_line(
f"PyObject *ret = {PREFIX}{init_fn.cname(emitter.names)}(self, args, kwds);"
emitter.emit_lines(
f"PyObject *self = {setup_name}(type);",
"if (self == NULL)",
" return NULL;",
f"PyObject *ret = {PREFIX}{init_fn.cname(emitter.names)}(self, args, kwds);",
"if (ret == NULL)",
" return NULL;",
"return self;",
)
emitter.emit_lines("if (ret == NULL)", " return NULL;")
emitter.emit_line("return self;")
emitter.emit_line("}")


def generate_new_for_trait(cl: ClassIR, func_name: str, emitter: Emitter) -> None:
emitter.emit_line("static PyObject *")
emitter.emit_line(f"{func_name}(PyTypeObject *type, PyObject *args, PyObject *kwds)")
emitter.emit_line("{")
emitter.emit_line(f"if (type != {emitter.type_struct_name(cl)}) {{")
emitter.emit_line(
emitter.emit_lines(
"static PyObject *",
f"{func_name}(PyTypeObject *type, PyObject *args, PyObject *kwds)",
"{",
f"if (type != {emitter.type_struct_name(cl)}) {{",
"PyErr_SetString(PyExc_TypeError, "
'"interpreted classes cannot inherit from compiled traits");'
'"interpreted classes cannot inherit from compiled traits");',
"} else {",
'PyErr_SetString(PyExc_TypeError, "traits may not be directly created");',
"}",
"return NULL;",
"}",
)
emitter.emit_line("} else {")
emitter.emit_line('PyErr_SetString(PyExc_TypeError, "traits may not be directly created");')
emitter.emit_line("}")
emitter.emit_line("return NULL;")
emitter.emit_line("}")


def generate_traverse_for_class(cl: ClassIR, func_name: str, emitter: Emitter) -> None:
Expand Down Expand Up @@ -775,16 +781,18 @@ def generate_clear_for_class(cl: ClassIR, func_name: str, emitter: Emitter) -> N
def generate_dealloc_for_class(
cl: ClassIR, dealloc_func_name: str, clear_func_name: str, emitter: Emitter
) -> None:
emitter.emit_line("static void")
emitter.emit_line(f"{dealloc_func_name}({cl.struct_name(emitter.names)} *self)")
emitter.emit_line("{")
emitter.emit_line("PyObject_GC_UnTrack(self);")
# The trashcan is needed to handle deep recursive deallocations
emitter.emit_line(f"CPy_TRASHCAN_BEGIN(self, {dealloc_func_name})")
emitter.emit_line(f"{clear_func_name}(self);")
emitter.emit_line("Py_TYPE(self)->tp_free((PyObject *)self);")
emitter.emit_line("CPy_TRASHCAN_END(self)")
emitter.emit_line("}")
emitter.emit_lines(
"static void",
f"{dealloc_func_name}({cl.struct_name(emitter.names)} *self)",
"{",
"PyObject_GC_UnTrack(self);",
# The trashcan is needed to handle deep recursive deallocations
f"CPy_TRASHCAN_BEGIN(self, {dealloc_func_name})",
f"{clear_func_name}(self);",
"Py_TYPE(self)->tp_free((PyObject *)self);",
"CPy_TRASHCAN_END(self)",
"}",
)


def generate_methods_table(cl: ClassIR, name: str, emitter: Emitter) -> None:
Expand Down Expand Up @@ -933,10 +941,12 @@ def generate_getter(cl: ClassIR, attr: str, rtype: RType, emitter: Emitter) -> N

if not always_defined:
emitter.emit_undefined_attr_check(rtype, attr_expr, "==", "self", attr, cl, unlikely=True)
emitter.emit_line("PyErr_SetString(PyExc_AttributeError,")
emitter.emit_line(f' "attribute {repr(attr)} of {repr(cl.name)} undefined");')
emitter.emit_line("return NULL;")
emitter.emit_line("}")
emitter.emit_lines(
"PyErr_SetString(PyExc_AttributeError,",
f' "attribute {repr(attr)} of {repr(cl.name)} undefined");',
"return NULL;",
"}",
)
emitter.emit_inc_ref(f"self->{attr_field}", rtype)
emitter.emit_box(f"self->{attr_field}", "retval", rtype, declare_dest=True)
emitter.emit_line("return retval;")
Expand All @@ -955,13 +965,13 @@ def generate_setter(cl: ClassIR, attr: str, rtype: RType, emitter: Emitter) -> N

deletable = cl.is_deletable(attr)
if not deletable:
emitter.emit_line("if (value == NULL) {")
emitter.emit_line("PyErr_SetString(PyExc_AttributeError,")
emitter.emit_line(
f' "{repr(cl.name)} object attribute {repr(attr)} cannot be deleted");'
emitter.emit_lines(
"if (value == NULL) {",
"PyErr_SetString(PyExc_AttributeError,",
f' "{repr(cl.name)} object attribute {repr(attr)} cannot be deleted");',
"return -1;",
"}",
)
emitter.emit_line("return -1;")
emitter.emit_line("}")

# HACK: Don't consider refcounted values as always defined, since it's possible to
# access uninitialized values via 'gc.get_objects()'. Accessing non-refcounted
Expand Down
Loading